But if I try to add another camera to the list, I get no response.
def handle_event("camera_selected",
%{"_target" => ["camera_selected"],
"camera_selected" => camera_id}, socket) do
camera_id = String.to_integer(camera_id)
camera = Cameras.get_camera!(camera_id)
# This does not work
#socket = assign(socket, selected_cameras: [camera] )
# Neither does this
socket = stream(socket, :selected_cameras, Cameras.list_cameras(), reset: true)
{:noreply, socket}
end
What can I do to tell LiveView that I have a new list of items I want it to render?
Also, just to be sure: is grid-basic really a grid cell or is that the parent? If it’s the parent the iterator should be on <.small_card>. Just checking, though, as the naming seems odd, apologies if you know that already.
Well, not entirely. The selected camera is added to :selected_cameras, but the existing list is not there. I want to prepend this new camera to the list, not replace it.
After debugging a bit, I noticed that the :selected_cameras array is empty within the “add_camera” event handler.
How can I make sure the existing list is present?
This code lives inside my MyAppWeb.WizardLive.Form, which is an LiveComponent.
def handle_event("add_camera", _params, socket) do
camera_id = socket.assigns.camera_id_selected
camera = Cameras.get_camera!(camera_id)
# selected_cameras are not available in the socket.assigns.
# I.e. the following line will return an empty list.
IO.inspect(socket.assigns.streams.selected_cameras,
label: "BEFORE insert")
socket = stream_insert(socket, :selected_cameras, camera)
# After adding a camera here, it is available and rendered in the view.
# When I add a camera, it replaces what I have added to the list previously.
IO.inspect(socket.assigns.streams.selected_cameras,
label: "AFTER insert")
{:noreply, socket}
end
The LiveComponent is mounted like this:
defmodule MyAppWeb.WizardLive.Summary.Edit do
use MyAppWeb, :live_view
alias MyAppWeb.Wizard.Summary
alias MyAppWeb.Wizard
@impl true
def mount(_params, _session, socket) do
socket =
socket
|> assign(:summary, %Summary{})
{:ok, socket }
end
@impl true
def render(assigns) do
~H"""
<div class="page-container">
<.live_component module={MyAppWeb.WizardLive.Form} />
</div>
Thanks for your suggestion!
I tried this update to the parent element, but I still got the same result.
The streams.selected_cameras is always empty at the start of the handle_event.
Here, you can see how I initiated the selected_cameras stream.
However, the assign_selected_cameras/1 is not triggered after I select a camera, so I don’t think that’s the cause of the empty list.
defmodule MyAppWeb.WizardLive.Form do
use MyAppWeb, :live_component
import Phoenix.HTML.Form
@impl true
def update(assigns, socket) do
{
:ok,
socket
|> assign_selected_cameras()
}
end
defp assign_selected_cameras(socket) do
IO.puts "ASSIGN SELECTED CAMERAS"
stream(socket, :selected_cameras, [])
end
What do you mean by empty? Do you mean that inside your handle_event(... you can’t see the contents of the stream? Like LostKobrakai mentioned, that’s how streams work. You can use
stream: set the contents of the stream. Will add new items to an existing stream, but will not remove items.
stream_insert: add / update items
stream_delete: remove items
stream(..., reset: true) to flush out all previous items and set the list to what you provide
If you need access to the existing cameras inside of your LiveView handle_event functions, you’ll have to switch from using streams to using regular assigns.
If I missed what your problem is, could you start over a bit and explain the flow a bit more? I think I may be confused about what you’re trying to achieve.