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

johnp
Running the examples in chapter 5 c under pytest 5.4.1 causes an AttributeError: ‘module’ object has no attribute ‘config’. In particula...
New
ianwillie
Hello Brian, I have some problems with running the code in your book. I like the style of the book very much and I have learnt a lot as...
New
herminiotorres
Hi! I know not the intentions behind this narrative when called, on page XI: mount() |&gt; handle_event() |&gt; render() but the correc...
New
adamwoolhether
I’m not quite sure what’s going on here, but I’m unable to have to containers successfully complete the Readiness/Liveness checks. I’m im...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
Charles
In general, the book isn’t yet updated for Phoenix version 1.6. On page 18 of the book, the authors indicate that an auto generated of ro...
New
adamwoolhether
Is there any place where we can discuss the solutions to some of the exercises? I can figure most of them out, but am having trouble with...
New
EdBorn
Title: Agile Web Development with Rails 7: (page 70) I am running windows 11 pro with rails 7.0.3 and ruby 3.1.2p20 (2022-04-12 revision...
New
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New
roadbike
From page 13: On Python 3.7, you can install the libraries with pip by running these commands inside a Python venv using Visual Studio ...
New

Other popular topics Top

Devtalk
Hello Devtalk World! Please let us know a little about who you are and where you’re from :nerd_face:
New
Devtalk
Reading something? Working on something? Planning something? Changing jobs even!? If you’re up for sharing, please let us know what you’...
1050 21151 394
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
rustkas
Intensively researching Erlang books and additional resources on it, I have found that the topic of using Regular Expressions is either c...
New
AstonJ
Saw this on TikTok of all places! :lol: Anyone heard of them before? Lite:
New
AstonJ
Biggest jackpot ever apparently! :upside_down_face: I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
New
PragmaticBookshelf
Author Spotlight: Peter Ullrich @PJUllrich Data is at the core of every business, but it is useless if nobody can access and analyze ...
New
PragmaticBookshelf
Fight complexity and reclaim the original spirit of agility by learning to simplify how you develop software. The result: a more humane a...
New

Sub Categories: