8
votes

Sorry for the long post, I tried to give all the information and explain what I have already tried.

Problem: I put a classic phoenix view into a liveview. While everything seems fine, the echart just vanishes as soon as it's finished painting. There seems to be no way to get it back.

Here is my graph. As you can see, I try to also hook it to the phx:update-event. But that doesn't help... graph.js:

updateGraph = function() {
  console.log("updating the graph...")
  let device_name = document.getElementById('device-name').value;
  let series_data = document.getElementById('history_chart_data').dataset.series;

  series_data = JSON.parse(series_data);

  // draw chart
  window.myChart.setOption({
    [chart options omitted]
  });
}

initGraph = function() {
  // initialize echarts instance with prepared DOM
  window.myChart = echarts.init(document.getElementById('history_chart'), 'light');
  updateGraph();
}

document.addEventListener('DOMContentLoaded', initGraph, false);
document.addEventListener('phx:update', updateGraph);

Here is the html (graph.html.leex). As you can see I even put the data in another div, just to be safe.

    <%= if assigns[:ttnmessages] do %>
      <script src="<%= Routes.static_path(DatabaumWeb.Endpoint, "/js/jcharts.min.js") %>"></script>
      <script src="<%= Routes.static_path(DatabaumWeb.Endpoint, "/js/moment.min.js") %>"></script>
      <script type="text/javascript" src="<%= Routes.static_path(DatabaumWeb.Endpoint, "/js/graph.js") %>"></script>


      <div id="history_chart" style="width: 100%;height:50vh;"></div>
      <div id="history_chart_data" data-series="<%= dataSeries(@ttnmessages, @graph_data) %>"></div>
    <% end %>

And the liveview

defmodule AppWeb.ConsoleLive do
  use Phoenix.LiveView
  alias AppWeb.ConsoleView
  alias App.API

  def render(assigns) do
    Phoenix.View.render(ConsoleView, "index.html", assigns)
  end


  @doc """
  Graph
  """
  def mount(session = %{params: %{"hardware_serial" => hardware_serial, "graph" => form}, user: current_user}, socket) do
    AppWeb.Endpoint.subscribe("TtnMessages")
    if connected?(socket), do: :timer.send_interval(1000, self(), :tick)

    ttnmessages = API.list_ttnmessages(hardware_serial, form)
    message = List.last(ttnmessages)
    devices = API.list_message_devices(current_user)
    device = API.get_device_by_serial(hardware_serial);
    graph_data = form
                 |> Enum.reject(fn {_k, v} -> v != "true" end)
                 |> Enum.map(fn {k, _v} -> k end)
                 |> Enum.to_list()

    session = Map.merge(session, %{
      devices: devices,
      ttnmessages: ttnmessages,
      message: message,
      device: device,
      graph_data: graph_data,
      message_ago: message_ago(message.inserted_at)
    })

    {:ok, assign(socket, session)}
  end

 #[Omitted two other mount methods, which are not called in this case]

  # updates the info when the device has last been seen.
  def handle_info(:tick, socket) do
    message = socket.assigns[:message]
    {:noreply, assign(socket, message_ago: message_ago(Map.get(message, :inserted_at)))}
  end

  #new message arrives, this is not responsible for my issue because this happens max. once per minute
  def handle_info(%{event: "new", payload: %{message: message}} = a, socket) do
    message = update_message(message, socket.assigns.message)
    devices = Enum.map(socket.assigns.devices, &update_device(&1, message))

    {:noreply, assign(socket, devices: devices, message: message)}
  end

  def handle_info(_broadcast, socket), do: {:noreply, socket}


  #  update the message if necessary
  defp update_message(message = %{hardware_serial: hs}, socket_message = %{hardware_serial: hs}), do: message
  defp update_message(_message, socket_message), do: socket_message


  defp update_device(_device= %{hardware_serial: hs}, _message = %{hardware_serial: hs}), do: API.get_device_by_serial(hs)
  defp update_device(device, _message), do: device

  defp message_ago(nil), do: "never"
  defp message_ago(date) do
    {:ok, ago} = Timex.Format.DateTime.Formatters.Relative.relative_to(date, Timex.now(), "{relative}", "de")
    ago
  end

end

The ttnmessages are never even updated. The ttnmessage is updated rarely. The tick is not responsible, I tried disabling that.

The chart before it vanishes (during page load) The graph just before it vanishes and afterwards And afterwards The interesting thing is that when I try to edit the element css and e.g. add a red background color, that when the tick hits.

Calling window.updateGraph() from the browser console does not make the graph reappear, but prints out updating the graph....

1

1 Answers

8
votes

As Chris McCord mentioned on Github, I had to insert phx-update="ignore" into the graph html. This fixed the issue and made me very happy.