I have an issue in reliably getting the appropriate LiveComponent rendering to occur when changing a schema value in the DB via Repo.update and immediately re-rendering from a Repo.all DB query. The re-render intermittently works properly, but mostly does not, primarily when changing a class struct archived value back to its default false value. Changing selected state does not have the issue.
I first thought that the DB query was returning old values, since the query occurred immediately after the update. Refreshing the page always results in correct rendering.
I exposed the modified struct values in the UI for debugging purposes, and logged the query results to confirm that the DB returns the proper data.
The images below show default state, then changing archived state to true, followed by changing archived state back to false but the archivedLiveComponent is rendered rather than the default. In addition, intermittently, the default LiveComponent is rendered when the archived state is set to true. The DB query provides a sorted response, with archived components at the bottom.
Here is the for comprehension code from a HEEx file, for rendering default, archived, and selected states (and displaying archived state for debugging purposes). Note, the selected state always renders properly.
<%= for class <- @classes do %>
Class: <%= class.title %> - Archived <%= class.archived %>
<%= if class.archived do %>
<.live_component module={RitoWeb.Components.ArchivedClass} id={class.id} class={class} user={@user} username={@username} color={class.color_code} back_color="#f0f0f0" />
<% else %>
<%= if Rito.Util.class_selected?(class.id, @selected_class) do %>
<.live_component module={RitoWeb.Components.Class} id={class.id} class={class} user={@user} username={@username} color={class.color_code} selected="true" back_color="#e7facc" />
<% else %>
<.live_component module={RitoWeb.Components.Class} id={class.id} class={class} user={@user} username={@username} color={class.color_code} back_color="#fff" />
<% end %>
<% end %>
<% end %>
<%= for class <- @classes do %>
<div id={"class-item-" <> class.id}>
Class: <%= class.title %> - Archived <%= class.archived %>
# ...
In your original example the immediate text is not keyed in any way, and as far as I understand, it’s the problem. Google for keyed vs non-keyed DOM updates for more info.
Thank you. I first wrapped a div with an id around the immediate text and the LiveComponent render command, and removed id from the LiveComponent’s wrapping div, causing an error. I then included both the wrapping div and passing an id parameter with the LiveComponent render, and the rendering problems disappeared.
In summary, adding a wrapping div with an id in the for comprehension and removing the id= from the LiveComponent’s wrapping div, while passing an id attribute in the LiveComponent render command, will allow the for comprehension to work properly.
Since the problem I identified occurs even with no immediate text in the for comprehension, I think there continues to be an issue where passing an id attribute in the LiveComponent render command, should allow proper DOM manipulation.
I followed up with removing the immediate text in the for comprehension and all works well. Here is the working for comprehension with wrapping div:
<%= for class <- @classes do %>
<%= if class.archived do %>
<div id = {class.id}>
<.live_component module={RitoWeb.Components.ArchivedClass} class={class} user={@user} username={@username} color={class.color_code} back_color="#f0f0f0" id={class.id} />
</div>
<% else %>
<%= if Rito.Util.class_selected?(class.id, @selected_class) do %>
<div id = {class.id}>
<.live_component module={RitoWeb.Components.Class} class={class} user={@user} username={@username} color={class.color_code} selected="true" back_color="#e7facc" id={class.id} />
</div>
<% else %>
<div id = {class.id}>
<.live_component module={RitoWeb.Components.Class} class={class} user={@user} username={@username} color={class.color_code} back_color="#fff" id={class.id} />
</div>
<% end %>
<% end %>
<% end %>
Here is the working LiveComponent wrapping div with no id=: