wktdev

wktdev

The image below is an app that I am working on and attempting to add a feature to.

https://imgur.com/a/f1dEP0E

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.

Showing Posts 1 to 10

wktdev

wktdev OP

Writing all this out made me realize I need to be working exclusively with “params” instead of “socket”

jswanner

jswanner

@wktdev, I’m assuming you have a handle_info/2 callback 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

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 of atomParam in the socket anywhere, so subsequent refreshes of testbeds can’t possibly maintain the same order.

wktdev

wktdev OP

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 OP

  def handle_info({TestBeds, [:testbed | _], _}, socket) do
    # IO.inspect("_______________SOCKET")
    # IO.inspect(socket)
    {:noreply, assign(socket, testbeds: TestBeds.list_testbeds())}
  end
wktdev

wktdev OP

I tried adding a video to make this more clear but the forum doesn’t let me.

garrison

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 status is 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

wktdev OP

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

jswanner

That is replacing your previously sorted testbeds with a new list that’s no longer using the user-specified sort order

wktdev

wktdev OP

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


    cache = socket.testbeds
    {:noreply, assign(socket, testbeds: cache)}

It’s all a dead end.

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews