Search code examples
elixirphoenix-frameworkphoenix-live-view

why phoenix liveview update/assign message make client contenteditable value revert?


With Phoenix live view document I add a live page for writing a realtime form app. There is very simple demo:

<h2>Hello</h2>

Counter is222: <%= @counter %>
<hr>

<button phx-click="dec">-</button>
<button phx-click="inc">+</button>

<table border="1">
  <tr>
    <th contenteditable="true">Month</th>
    <th>S1</th>
    <th>S2</th>
  </tr>
  <tr>
    <td contenteditable="true">January</td>
    <td contenteditable="true">$100</td>
    <td contenteditable="true">$10220</td>
  </tr>
</table>

Server side code (just like document):

defmodule TicTacWeb.MemberSchedulerLive do
  use Phoenix.LiveView


  def render(assigns) do
    TicTacWeb.PageView.render("member_scheduler.html", assigns)
  end

  def mount(_, socket) do
    {:ok, assign(socket, %{counter: 100})}
  end

  def handle_event("inc", _, socket) do
    {:noreply, update(socket, :counter, fn(x) -> x + 1 end)}
  end

  def handle_event("dec", _, socket) do
    IO.puts("item")
    {:noreply, update(socket, :counter, fn(x) -> x - 1 end)}
  end

end

The problem is <td contenteditable value will be revert after I click - or + emit a message to server.

  1. why - or + affect <td>'s value? Is't minimize change modified dom data?
  2. Is there a best practice for such scene?

Thanks!

UPDATE
After add contenteditable as data model, it was still not work, such as:
1. html snippet

    ....
    <td contenteditable="true">$100</td>
    <td contenteditable="true" phx-blur="somedata"><%=@somedata%></td>
  </tr>
</table>
  1. backend
  ...
  def mount(_, socket) do
    {:ok, assign(socket, %{counter: 100, somedata: "$001"})}
  end

The @somedata also revert to $001 if click - or +.


Solution

  • why - or + affect <td>’s value?

    It’s vice versa. They do not affect <td>’s value, on the contrary, it sends the diff between the previous state and the updated state and the frontend applies this diff.

    LiveView has no idea about your local changes with the contenteditable="true" and hence it resets everything to its original state, save for :counter that gets updated. To support contenteditable="true" you need to make these <td>’s a part of data model so that LiveView is aware about the changes in there.