I have a Live view that renders a
and injects a script file for that page. The script contains a function that renders a chart on the div based on the data provided to the div via a data attribute. It all works great the first time, but when I change one filter, the live view gets re-rendered and now the chart is all white (no chart rendered). I’m pretty new to Phoenix so I might be doing something wrong, but just in case, I’ll leave some code here.
/views/cash_flow_view.ex
defmodule Proj.CashflowView do
use ProjWeb, :view
def date_group_filters() do
[
"By Month": :by_month,
"By Quarter": :by_quarter,
"By Year": :by_year
]
end
def render("scripts.html", _assigns) do
~E(<script src="./js/charts.js"></script>)
end
end
live/cashflow_live_view.ex
defmodule ProjWeb.CashflowLiveView do
use Phoenix.LiveView
alias Poison
alias ProjWeb.CashflowView
alias Proj.Cashflow
def render(assigns) do
IO.inspect "RENDERING AGAIN"
IO.inspect assigns.cashflow
~L"""
<h3>Cash flow</h3>
<%= CashflowView.render("filters.html", assigns: assigns) %>
<div id="chart" data-cashflow="<%= Poison.encode!(assigns.cashflow) %>"></div>
<%= CashflowView.render("scripts.html", assigns: assigns); %>
"""
end
def mount(session, socket) do
{:ok, assign(socket, session)}
end
def handle_event("update_filters", %{"filters" => filters}, socket) do
cashflow = case Map.get(filters, "date_group") do
"by_month" ->
Cashflow.cashflow_by_month(socket.assigns.user_id)
"by_quarter" ->
Cashflow.cashflow_by_quarter(socket.assigns.user_id)
"by_year" ->
Cashflow.cashflow_by_year(socket.assigns.user_id)
end
{:noreply, assign(socket, cashflow: cashflow)}
end
end
/scr/chart.js
import Taucharts from "taucharts";
import tooltip from "taucharts/dist/plugins/tooltip"
export var Chart = {
render: function() {
const chartDiv = document.querySelector('#chart');
const data = JSON.parse(chartDiv.dataset.cashflow);
const chart = new Taucharts.Chart({
data: data,
type: 'line',
x: 'date',
y: 'amount',
color: 'type',
guide: {
x: {label: {text: 'Month', padding: 35}, padding: 20},
y: {label: 'Cashflow', padding: 20},
padding: {b: 70, l: 70, t: 10, r: 10},
showGridLines: 'y'
},
plugins: [
tooltip()
]
});
chart.renderTo('#chart');
}
}
setTimeout(() => Chart.render(), 1000)
My 2 questions would be:
- Is there a way to avoid having to use that setTimeout? If I don’t use it then the chart probably never gets rendered.
- How can I make sure that inside the live view I can get access to chart? and call it’s methods from there?
Thanks!