Live view along with checkbox doesn't update view

My desired behavior is to update a html.leex table depending of whether or not I have a checkbox checked.
The problem is that my leex table has erractics behaviors on browsers.
On Safari, the toggle doesn’t change visually, yet the table update itself correctly.
On Firefox, it’s the toggle that work well, and the table that has updated data yet doesn’t update itself.

Here is my module

@impl true
  def mount(_params, _session, socket) do
    socket = assign(socket, examens: []) # As mount is called twice, this is the default state
    socket =
      case connected?(socket) do # This piece is executed only once, while mount itself is called twice
        true -> setup_socket_assigns(socket)
        false -> socket
      end
    {:ok, socket}
  end

  @impl true
  def handle_event("hidecheck", _params, %{assigns: %{checked: checked}} = socket) do
    socket = assign(socket, checked: !checked) # Update toggled
    IO.inspect(socket.assigns.checked, label: "\n\nStatus of the checkbox")

    socket =
      case socket.assigns.checked do
        true -> hide_common_exams(socket)
        false -> show_every_exams(socket)
      end
    #IO.inspect(socket.assigns.__changed__, label: "List of changes in assigns")
    #IO.inspect(Enum.count(socket.assigns.examens), label: "Number of exams")
    {:noreply, socket}
  end

  # Setup the socket when connected. Pipe compatible
  def setup_socket_assigns(socket) do
    IO.inspect("Socket connected, second mount call, setting up exams")
    socket
    |> assign(checked: false)
    |> show_every_exams()
  end

  # If toggle is active, this with do the assign in the socket. Pipe compatible
  def hide_common_exams(socket) do
    IO.inspect("Hide commons exams")
    examens = Examens.list_unique_examens()
    socket
    |> assign(examens: examens)
    #|> IO.inspect()
  end

  # If toggle is not active, this will do the assign in the socket. Pipe compatible
  def show_every_exams(socket) do
    IO.inspect("Show every exams")
    examens = Examens.list_examens()
    socket
    |> assign(examens: examens)
    #|> IO.inspect()
  end

My table

<h2>Liste des examens</h2>

<% IO.inspect @examens %> # Print updated data

<table>
  <thead>
    <tr>
      <th>Accession Number</th>
      <th>Nom</th>
      <th>Patient ID</th>
      <th>Naissance</th>
      <th>AET</th>
      <th>Type</th>
    </tr>
  </thead>
  <tbody>
    <%= for examen <- @examens do %>
        <tr>
            <td><%= examen.accession_number %></td>
            <td><%= examen.name %></td>
            <td><%= examen.patient_id %></td>
            <td><%= dayFormatter(examen.birthday) %></td>
            <td><%= examen.aet %></td>
            <td><%= examen.type %></td>
        </tr>
    <% end %>
  </tbody>
</table>

Live.html.heex (This toggle is straight up taken from W3C)

<div class="hidetoggle">
    <!-- Rounded switch for merging boards-->
    <label class="switch">
      <input type="checkbox" phx-click="hidecheck" {checked: @checked}>
      <span class="slider round"></span>
    </label>
    <h3 class="labeltoggle">Hide examens both in modalities and archives</h3>
  </div>

hello , i think your error is on this line on the hidecheck event
socket = assign(socket, checked: !checked) # Update toggled

remember that at this point the socket has the updated check property updated, but after that
you do

socket =
case socket.assigns.checked do
true → hide_common_exams(socket)
false → show_every_exams(socket)
end

so the socket is not the same you assign earlier is the one pass down to the function

you can pipe the changes

socket =
case socket.assigns.checked do
true → hide_common_exams(socket)
false → show_every_exams(socket)
end
|> assign(socket, checked: !checked)

Thanks for trying, but this part has the precise behavior I wish (inverse the bool, then compute result according to it).
I know because each time I toggle, my examen list is correctly updated, both in the handle_event (the commented IO.inspect) and in the template (the IO.inspect @examens above the table in html.leex)

It just happen than even if the template has new data and is called (the IO.inspect print logs just fine), the webpage is not updated correctly in my browsers. Seem like a problem due to web browsers, but I didn’t read anything about limited supports for some browsers in the LiveView documentation.

After more testing, I found out that commenting this line

socket = assign(socket, checked: !checked) # Update toggled

Allow safari to correctly display the checkbox. I truly don’t get how an assign in the socket could reset the checkbox status. The boolean isn’t updated, so I don’t see why.

In fact, it seem that no matter the browser, only one thing can update the view. Either the browser when checking the box, or the liveview updating the array. Both can’t do it at the same time. I seldomly got the toggle working without array update on Firefox, or Array without toggle on Safari.

Ok I am no dev web, so it took a while to get more info, but look like Firefox received the update array well, according to the web console. However, it raised a “Uncaught DOMException: String contains an invalid character”

Here is the full execption, even if do not know yet what it mean

Uncaught DOMException: String contains an invalid character dom.js:276:37
    mergeAttrs dom.js:276
    mergeFocusedInput dom.js:292
    onBeforeElUpdated dom_patch.js:181
    morphEl morphdom-esm.js:490
    morphChildren morphdom-esm.js:603
    morphEl morphdom-esm.js:505
    morphChildren morphdom-esm.js:603
    morphEl morphdom-esm.js:505
    morphChildren morphdom-esm.js:603
    morphEl morphdom-esm.js:505
    morphChildren morphdom-esm.js:603
    morphEl morphdom-esm.js:505
    morphdom2 morphdom-esm.js:720
    perform dom_patch.js:95
    time live_socket.js:229
    perform dom_patch.js:94
    performPatch view.js:374
    update view.js:480
    time live_socket.js:229
    update view.js:477
    hookReply view.js:674
    applyDiff view.js:227
    pushWithReply view.js:673
    after live_socket.js:812
    requestDOMUpdate live_socket.js:247
    pushWithReply view.js:672
    matchReceive push.js:76
    forEach self-hosted:164
    matchReceive push.js:76
    startTimeout push.js:107
    trigger channel.js:278
    Channel channel.js:70
    trigger channel.js:278
    onConnMessage socket.js:510
    decode serializer.js:25
    decode self-hosted:1118
    onConnMessage socket.js:497
    onmessage socket.js:221
    (Asynchrone : EventHandlerNonNull)
    connect socket.js:221
    doConnect live_socket.js:208
    connect live_socket.js:212
    <anonyme> app.js:38
    <anonyme> app.js:5011

And here is the data that was pushed to add entry to the array:

2: Array(6) [ "A000001", "SIMPSON^Homer", "004025792", … ]
0: "A000001"
1: "SIMPSON^Homer"
​​​​​
2: "004025792"
​​​​​
3: "07/06/1965"
​​​​​
4: "RADIO_PGR"
​​​​​
5: "archive"
​​​​​
length: 6
​​​​​
<prototype>: Array []
​​​​
3: Array(6) [ "A000002", "SIMPSON^Bart", "004025756", … ]
​​​​​
0: "A000002"
​​​​​
1: "SIMPSON^Bart"
​​​​​
2: "004025756"
​​​​​
3: "07/12/2005"
​​​​​
4: "ECHO_PGR"
​​​​​
5: "archives"
​​​​​
length: 6

Safari doesn’t raise.
Right now I think I’ll try with a classic button instead of a checkbox

OK I made everything work, the problem was that leex was depreciated and renaming live.html.leex into heex solved everything.

That was rather frustrating, but at least now it works.
And the worst is that I put the correct name in my problem.
Just in case tho, the input should be

<input type="checkbox" phx-click="hidecheck" checked={@checked}>

Watch out for attibute settings in templates.