willc0de4food
Automatically chart async data in liveview without user interaction
Howdy,
I’m struggling with something that seems like it should be simple. I would like to fetch some data via async when the page loads, and then once loaded, graph that data with Highcharts. Everything I’ve read has indicated that you need to setup a hook that will allow you to pass the data from the server to the JS, and you use a handle_event to trigger push_event() with the data. I don’t have a user interaction to trigger the handle_event, I just want the graph to load once the data is ready. I tried adding the push_event() to handle_async , but nothing happens in the JS hook. I have added a dbg() line to verify that the data is being received in the handle_async.
What am I missing? ![]()
Some code:
def mount() do
...
|> start_async(:points, fn -> Tokens.generate_chart_data() end)
...
end
def handle_async(:points, {:ok, points}, socket) do
dbg(points)
{:noreply, push_event(socket, :points, %{points: points})}
end
def render(assigns) do
~H"""
...
<div class="mt-4 flex flex-row w-full">
<div id="graph" phx-hook="Graph"></div>
</div>
"""
end
var Hooks = {};
Hooks.Graph = {
mounted() {
logToConsole('mounted');
},
updated() {
logToConsole('updated');
this.handleEvent("points", ({points}) => logToConsole(points);
}
}
let logToConsole = (action) => {
console.log('*********************', action);
}
Marked As Solved
willc0de4food
Update: I got it working without hooks! It was as straight forward as it seemed like it should be, I just didn’t know what I didn’t know. The final working product:
live view:
def mount(params, _session, socket) do
...
socket =
socket
...
|> start_async(:points, fn -> Tokens.generate_chart_data() end)
{:ok, socket}
end
def handle_async(:points, {:ok, points}, socket) do
{:noreply, push_event(socket, "graph", %{points: points})}
end
def render(assigns) do
~H"""
...
<div id="graph"></div>
"""
end
app.js:
window.addEventListener(
"phx:graph",
e => {
if (e.detail?.points) {
Highcharts.chart('graph', { ... });
}
}
)
That’s it ![]()
Also Liked
cmo
Firstly, you need to put this.handleEvent("points", ({points}) => logToConsole(points); in mounted.
You can set it up so that the process receives a message every x seconds, which you handle in handle_info and can trigger the start_async from there.
You can send the message every x seconds with :erlang.send_interval(Time, Destination, Message) or trigger it each time you process the message in handle_info/handle_async. That is Process.send_after(...)), called once in mount and then again in handle_info
If the data is on some publication you could subscribe to that in your liveview.
cmo
I’d still go with a hook as often you want to dispose of the chart in destroyed and/or modify it in update and push the event to the specific chart.
So sorry for the timer stuff, I had realtime chart on the brain from a post on the discord and conflated the two.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










