djantea

djantea

Building Table Views with Phoenix LiveView: Add a load indicator that will start on user event (click) and end when data finishes loading

Hello @pullrich,

I am following he book, which is great because is helping me building tabelar UI fast. Thank you.

The ideea to separate the individul Phoenix.LiveComponents (sorting, filtering, pagination) from the main LiveView by sending events is great, but it does introduce a UX problem: there is no load indictor that will cover the whole time, starting with the user event (e.g. click on the page number of the pagination form) and ending when the result (the paginated meerkat data) is sent back to the browser.

The current behavior is that the load indicator starts when the user clinks the button and stops when the push event is handled by the handle_event callback. But in the background, the processing of actually fetching the data continues by sending an :update event to the parent LiveView, changing the URI params with push_patch and finally responding to the the URI params change with handle_params. All this subsequent background processing is not covered by the load indicator, and this is normal, as this is a custom way of processing the data. So we need to manually start and stop the progress indicator ourselves.

I tried to solve this problem myself but did not succeed:

I can start the load indicator (the topbar displayed at the top of the page) by replacing:

<div phx-click="show_page"​
     phx-value-page={page_number}​
     phx-target={@myself}​
     class={if current_page?, do: "active"} >

with

<div phx-click={JS.push("show_page") |> JS.dispatch("phx:page-loading-start")}
     phx-value-page={page_number}​
     phx-target={@myself}​
     class={if current_page?, do: "active"} >

But I cannot stop the indicator. I tried by adding this to MeowWeb.MeerkatLive.handle_params/3:

   ...
   |> push_event("phx:page-loading-stop", %{})
   ...

but it does not work. I see the event being sent to the browser through the web socket, but there is no effect, the progress indicator keeps going on.

Any ideas?

Marked As Solved

pullrich

pullrich

Author of Building Table Views with Phoenix LiveView

Hey @djantea ,

thank you for reading my book :slight_smile:

I must admit that it took me a good hour to find the problem here: If you push an event from the server to the client using push_event/3, then you don’t have to prefix the event name with phx: because LiveView does so automatically.

So, in your case, the client would receive the event phx:phx:page-loading-stop which doesn’t stop the loading bar. If you remove the phx: from your push_event/3-call, it should work :slight_smile:

Let me know if this fixed your problem :muscle:

Also Liked

djantea

djantea

Hy @pullrich,

Thank you for taking the time and for responding.

Yes, it solved my problem :slight_smile:

I also realized what the problem was, the next day after I posted the question.

Taking the solution one step further, I decided to use different, custom JavaScript events to be triggered for table loading, phx:table-loading-start and phx:table-loading-stop:

  • After the initial user event is handled by any of the three LiveComponents (clicking on the sort header, on the filter button, or on the page number), right after sending the :update event to the parent LiveView in handle_event/3, I trigger a phx:table-loading-start event:
    ...
    send(self(), {:update, opts})
    {:noreply, push_event(socket, "table-loading-start", %{})}
    ...
  • Then, in the parent LiveView, after the final data is available and is ready to be sent to the browser, in handle_params/3, I trigger a phx:table-loading-stop event:
  def​ handle_params(params, _url, socket) ​do​
    socket =
      socket
      |> parse_params(params)
      |> assign_meerkats()
      |> push_event("table-loading-stop", %{})

      {​:noreply​, socket}
  ​end

And then, I handle these event in JavaScript by starting and stopping the page loading progress indicator, while also preventing the handler of the LiveView’s phx:page-loading-stop event to stop the progress if it has been started by a phx:table-loading-start event:

window.tableLoading = false;

window.addEventListener('phx:table-loading-start', info => {
  window.tableLoading = true
  topbar.show()
})
window.addEventListener('phx:table-loading-stop', info => {
  window.tableLoading = false
  topbar.hide()
})

window.addEventListener("phx:page-loading-start", info => {
  topbar.show()
})
window.addEventListener("phx:page-loading-stop", info => {
  if (!window.tableLoading)
    topbar.hide()
})

I think this is a cleaner solution, because it separates the table loading events, which are spanning across more than one LiveView event → handle_event cycle, from LiveView events which are more fine grained.

But I admit its not the cleanest approach, and I am still looking to improve it.

I feel that more control over the page loading (and maybe other kinds of loading) events should be exposed by LiveView itself, for situations like this.

What do you think?

Where Next?

Popular Pragmatic Bookshelf topics Top

Alexandr
Hi everyone! There is an error on the page 71 in the book “Programming machine learning from coding to depp learning” P. Perrotta. You c...
New
HarryDeveloper
Hi @venkats, It has been mentioned in the description of ‘Supervisory Job’ title that 2 things as mentioned below result in the same eff...
New
brunogirin
When installing Cards as an editable package, I get the following error: ERROR: File “setup.py” not found. Directory cannot be installe...
New
Henrai
Hi, I’m working on the Chapter 8 of the book. After I add add the point_offset, I’m still able to see acne: In the image above, I re...
New
jwandekoken
Book: Programming Phoenix LiveView, page 142 (157/378), file lib/pento_web/live/product_live/form_component.ex, in the function below: d...
New
andreheijstek
After running /bin/setup, the first error was: The foreman' command exists in these Ruby versions: That was easy to fix: gem install fore...
New
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New
New
davetron5000
Hello faithful readers! If you have tried to follow along in the book, you are asked to start up the dev environment via dx/build and ar...
New
dachristenson
@mfazio23 Android Studio will not accept anything I do when trying to use the Transformations class, as described on pp. 140-141. Googl...
New

Other popular topics Top

AstonJ
What chair do you have while working… and why? Is there a ‘best’ type of chair or working position for developers?
New
brentjanderson
Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
AstonJ
Continuing the discussion from Thinking about learning Crystal, let’s discuss - I was wondering which languages don’t GC - maybe we can c...
New
DevotionGeo
I have always used antique keyboards like Cherry MX 1800 or Cherry MX 8100 and almost always have modified the switches in some way, like...
New
New
First poster: AstonJ
Jan | Rethink the Computer. Jan turns your computer into an AI machine by running LLMs locally on your computer. It’s a privacy-focus, l...
New
PragmaticBookshelf
Develop, deploy, and debug BEAM applications using BEAMOps: a new paradigm that focuses on scalability, fault tolerance, and owning each ...
New
PragmaticBookshelf
Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic. Sam Ruby @rubys ...
New
mindriot
Ok, well here are some thoughts and opinions on some of the ergonomic keyboards I have, I guess like mini review of each that I use enoug...
New

Sub Categories: