Synchronize Multiple Channel Clients
Learn how to synchronize our cart across multiple tabs and pages.
Synchronize our cart
Each shopper that joins our ShoppingCartChannel
does so on a private topic, like cart:123abc
. This cart ID is random and long, so we can uniquely identify a cart. To synchronize our cart across multiple tabs, we’ll use this topic. We’ll send the serialized version of our cart using Phoenix.PubSub
and intercept it in the ShoppingCartChannel
. It will only be received by Channel processes running with that same cart ID.
Let’s add the following code to the ShoppingCartChannel
module—we’ll walk through the critical parts.
# sneakers_23_cart/lib/sneakers_23_web/channels/shopping_cart_channel.exintercept ["cart_updated"]def handle_in("add_item", %{"item_id" => id}, socket = %{assigns: %{cart: cart}}) docase Checkout.add_item_to_cart(cart, String.to_integer(id)) do{:ok, new_cart} ->broadcast_cart(new_cart, socket, added: [id])socket = assign(socket, :cart, new_cart){:reply, {:ok, cart_to_map(new_cart)}, socket}{:error, :duplicate_item} ->{:reply, {:error, %{error: "duplicate_item"}}, socket}endenddef handle_out("cart_updated", params, socket) docart = get_cart(params)socket = assign(socket, :cart, cart)push(socket, "cart", cart_to_map(cart)){:noreply, socket}enddefp broadcast_cart(cart, socket, opts) do{:ok, serialized} = Checkout.export_cart(cart)broadcast_from(socket, "cart_updated", %{"serialized" => serialized,"added" => Keyword.get(opts, :added, []),"removed" => Keyword.get(opts, :removed, [])})end
The only change to the handle_in
function is the addition of a call to broadcast_cart/2
. This function leverages ...