简体   繁体   中英

Updating nested html element in LiveView of Phoenix application without rendering the whole component

I have the following leex template with a collection of cards and inside each card, there is a nested button. I would like to update the text on the button only without rendering again the whole component. Is it possible? I am stuck here. The idea is to send an update to this button but it's not clear how if possible at all. Or is another way would be assigning again the @repos to the socket?

<form phx-change="gsearch">
    <fieldset>
        <label for="name">Name</label>
        <input id="name" type="text" name="name" value="<%= @name %>"
               placeholder="Search repos..."
               autofocus autocomplete="off" phx-debounce="500" />

        <input class="button-primary" type="submit" value="Clear"/>
    </fieldset>
</form>

<%= unless @repos == [] do %>
<h2>Search Results</h2>

<div class="cont">
    <%= for repo <- @repos do %>
        <%= card do %>
            <%= card_header do %>
                <h2>Name: <%= repo.name %> Stars: <%= repo.stars %></h2>
                <%= if repo.description != nil do %>
                    <%= repo.description %>
                <% end %>
            <% end %>
            <%= card_body do %>
                <%= link repo.link, to: repo.link, target: "_blank" %>
                <button id="<%= repo.id %>"
                        class="button-primary fav"
                        phx-click="save"
                        phx-value-id="<%= repo.id %>"
                        phx-value-action="<%= if repo.liked do %>unlike<% else %>like<% end %>"
                        style="display: block">
                <%= if repo.liked do %>Remove<% else %>Add<% end %>
                </button>
            <% end %>
        <% end %>
    <% end %>
</div>
<% end %>

When I click the button, I do the job on the server side and then I want to update only this button in particular.

As it is clear from the code, buttons are located inside the card component which is just a div.

Is it possible to update just the button which I clicked?

Since you're using LiveView, updating the socket such that the new repos assign contains an updated target repo with a toggled liked attribute should do the trick. Here's one way of updating the assigns:

def handle_event("save", %{"id" => id}, socket) do
  # update repo in db
  # ...

  # then update repo in socket
  updated_socket =
    update(socket, :repos, fn repos -> 
      update_in(repos, [Access.filter(&(&1.id == id}}], fn repo ->                 
        %{repo | liked: !repo.liked}
      end)
    end)

  {:noreply, updated_socket}
end

I'd also suggest reading through the Managing State section of the LiveView docs. It's meant for LiveComponent and Heex, but should still be applicable and lays out the different options you have for state management.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM