Is `Enum.replace_at` authentic for updating socket.assigns?

Hi, Everyone:

I’m currently working on a project and I decided to give liveview a try. I’m so happy with it and thanks for all the contributions everyone made.

I’m posting to ask whether my approach is authentic. Here we go: (it’s an auction system)

data model

  • item: item has many bids
  • bid: bid belongs to an item

scenario

on the liveview page: I loaded all the items. (I’m not using temporary assign because I need to find a specific item later on)

when I click a specific item, a modal is popup, and I can create a new bid.
After the new bid is saved in the database, I want the bid number to be updated on the page.

I try to solve this with pubsub. After creating a bid, message is broadcasted to all subscriber including the liveview page.

In handle_info, I reload the bid association of the specific item. Then I use Enum.replace_at to replace that item in the items assign in the socket.

question

  1. I knew that if I used temporary assign, I can simply [item | items] to let liveview track the difference and replace specific item. what can I do to utilize the similar mechanism without using temporary assign?

  2. is it possible to use temporary assign in my use case? ( I need to find the detailed information of specific item after the initial rendering)

Thanks!

Doesn’t your bid have anid that you can use to locate and update it?

I would say just like @cmo, if your item has an id then you can just do

socket = put_in(socket.assigns.item_bids[item_id], bid).

Yes, but I only ever use assign or update to modify the socket. There is more going on under the covers than just putting values into the assigns map.

Thanks for the reply, I was wondering whether it’s possible to use [item| items] + prepend/append without temporary assign.
After experimenting a bit, it seems to be impossible.

data structure

[ 
%Item{}, 
%Item{}, 
           
%item{   bids: [%bid{}, %bid{}]  } 
]

I don’t think I can use put_in or replace_at because I need to traverse the list and find the specific item.
Right now, I solve it by reloading all items as a whole, but there’s room for optimization.

I can use Enum.map to return an updated list, but it still needs to traverse the whole list.

If its possible to index the collection it is easier to update:

def index_collection!(collection, key) do
  Enum.map(collection, fn item -> {Map.fetch!(item, key), item} end) |> Enum.into(%{})
end
> items = [%Item{id: 1, ...}, %Item{id: 2, ...}]
> index_collection!(items, :id)
%{1 =>  %Item{id: 1, ...}, ... } 

But you lose order, be aware of that.

1 Like

order is a must-have criteria. I think I will have to traverse the list. Also, I found that Enum.reject is used during deletion in liveview doc. I guess it’s ok when the list is not huge when pagination is involved.