wktdev
The image below is an app that I am working on and attempting to add a feature to.
Quick description of initial code
The items that are stacked on top of one another are called “testbeds” and these are pulled from Postgres via Ecto. They are then assigned to the socket, rendered and iterated through. TestBeds uses a pub-sub feature so when changes are made to this collection the changes are broadcast to other users.
def mount(_params, _session, socket) do
TestBeds.subscribe()
{:ok,
assign(socket,
testbeds: TestBeds.list_testbeds(), #Get Testbeds
# code ...
)}
end
Render
def render(assigns) do
~H"""
<body>
<div>
<%= for testbed <- Enum.filter(@testbeds, fn(item)-> item.group_id != nil end)|>Enum.sort_by(&("# {&1.group.name}#{&1.name}"), :asc) do %>
<%!-- code.... --%>
<% end %>
</div>
<%!-- code ..... --%>
</body>
"""
end
In the code above the testbeds are explicitly sorted by a property named group.name. The reason I am sorting it like this is because if I iterate and render testbeds with no sorting, the testbeds will automatically sort by the update_at property (and this change will be broadcast to other users) and this is not what I want. Choosing to sort it by group.name is arbritary, I could have used any property.
What is the problem?
You see those headers at the top? I want the user to be able to click each one and as a result the testbeds automatically sort by that columns data.
So far I have it partially working. I updated the testbeds with the previous sorting removed and so the code now looks like this:
<%= for testbed <- @testbeds do %>
<%!-- code.... --%>
<%-- Example of sorting applied to a heading. The actual code has about 12 of these --%>
<h2 class="info-button" phx-click="sort_by_string" phx-value-field="hardware"> Hardware</h2>
<%!-- code.... --%>
<% end %>
The code to sort the testbeds looks like this:
def handle_event("sort_by_string", %{"field" => field}, socket) do
atomParam = String.to_existing_atom(field)
IO.inspect atomParam
if socket.assigns[:sort_by_name_ascending] == false do
sorted_testbeds = Enum.sort_by(socket.assigns.testbeds, fn item -> Map.get(item, atomParam) end) #hardware is hard coded as an atom
{:noreply, assign(socket, testbeds: sorted_testbeds, sort_by_name_ascending: true)}
else
sorted_testbeds = Enum.sort_by(socket.assigns.testbeds, fn item -> Map.get(item, atomParam) end) |> Enum.reverse() #hardware is hard coded as an atom
dbg(sorted_testbeds)
{:noreply, assign(socket, testbeds: sorted_testbeds, sort_by_name_ascending: false)}
end
end
The Problem
The field titled Set Status (see image) has a button that lets the user make an update to a property of testbeds named status (in the image this is the button displaying Available or Taken). When this happens, the testbed order changes and re-orders based on the values in update_at property. I do not want this. I want the order of the testbeds to stay as-is and not to be broadcast to users. However, I do want the status update (the change from Available to Taken) to be broadcast. To be clear, when a user changes the status no sorting should be visibly made or broadcast but the status value change should be broadcast. The status values are Available and Taken (see image).
To make this worse, as mentioned, I have integrated the pub-sub feature so that when a user changes the status of a testbed, not only does the status change but the ordering is broadcast to everyone. I want the ordering to visibly stay as-is for any user that changes a testbed status.
The status code is here:
def handle_event("create-status", params, socket) do
# Create Record
%{"status" => status, "testbed_id" => testbed_id, "developer" => developer} = params
stripped_developer = String.trim(developer)
if stripped_developer === "" || String.trim(developer) === "" || String.trim(developer) === "None" do
{:noreply, assign(socket, developer: developer, name_warning: " (can't be empty or set to None)")}
else
TestBeds.get_test_bed!(testbed_id)
|> TestBeds.update_test_bed(%{status: status, developer: developer})
current_testbed = TestBeds.get_test_bed!(testbed_id)
StatusActions.create_status_action(%{
testbed_name: current_testbed.name,
testbed_value: testbed_id,
status: status,
developer: developer
})
{:noreply, assign(socket, developer: developer)}
end
end
The reset (Changes **Taken** back to **Available**) is here:
def handle_event("reset", %{"id" => id}, socket) do
testbed = TestBeds.get_test_bed!(id)
StatusActions.create_status_action(%{
testbed_name: testbed.name,
testbed_value: id,
status: "Available",
developer: testbed.developer
})
TestBeds.get_test_bed!(id)
|> TestBeds.update_test_bed(%{status: "Available", developer: "None"})
# {:noreply, socket}
{:noreply, assign(socket, testbeds: TestBeds.list_testbeds())}
end
Summary
When a user sorts data by clicking the headings. the testbeds should sort by column data and this sorting should not be broadcasted to other users. This currently works with one exception.
The exception
When a user changes the Status value sorting takes and is broadcast to other users. This should not happen.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #blog-post
- #ai
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
wktdev
Writing all this out made me realize I need to be working exclusively with “params” instead of “socket”
jswanner
@wktdev, I’m assuming you have a
handle_info/2callback in the LiveViews for handling the PubSub message, what are you doing in that callback? Are you refetching the testbeds from the database and not re-applying the user-defined sorting?al2o3cr
Not 100% following what the issue is, but one thing that jumped out was that the code in the handler for
"sort_by_string"doesn’t record the value ofatomParamin the socket anywhere, so subsequent refreshes oftestbedscan’t possibly maintain the same order.wktdev
That’s intended. I don’t want the sorting to be retained on refreshes ( I know their is a way to do this that is bound to a URL but I’m not doing it that way … maybe I should have, but I’m already going down this path).
wktdev
wktdev
I tried adding a video to make this more clear but the forum doesn’t let me.
garrison
Socket assigns are not retained on refreshes. It’s hard for us to be sure without more code, but it seems to me like he identified your problem:
When the
statusis updated, you are probably reloading the list of testbeds, right? And when that happens the sort order is reset because you’re not storing and re-applying the sort field after updating the list.wktdev
I’m looking for direction on how to fix it not just diagnose it. If this was React.js I could probably fix it in 20 min, but I’m not familiar with Liveview enough to be confident on how to untangle myself out of the box I’m in.
jswanner
That is replacing your previously sorted testbeds with a new list that’s no longer using the user-specified sort order
wktdev
I see it, I don’t know what to do about it so that I can retain the order and still change the status.
I tried playing around trying to cache the testbeds and edit it something like
It’s all a dead end.