dvartic

dvartic

Find pid of another LiveView for use in send_update

I am new to Elixir and Phoenix, so I apologize if the question is stupid.

I am developing an ecommerce site, and I have a cart drawer located in a layout, using LiveComponent.

After adding an item to cart from another component, that as I understand it, lives in another process, I want to send an update to this LiveComponent so that it updates without a page refresh or navigation.

I found send_update which seems to do what I want Phoenix.LiveView — Phoenix LiveView v1.0.0-rc.1

To use this, I need to find PID of this other Liveview. Things I tried:

  • Process.info(self()) Does not return assigned name of the process
  • Process.register(self(), :cart_liveview) Fails due to a name already existing
  • Using the id that I pass to live_render from the layout, to render everything. Does not find it.

I am using Process.whereis to get PID from name.

Relevant code:

handle_event snippet on product page

      # Save
      properties_enc = Jason.encode!(values)
      Carts.add_to_cart(cart_id, product_id, properties_enc)
      # PID<0.4190.0>
      pid = Process.whereis(:cart_liveview)
      send_update(CartModal, id: "cart_modal", hello: "from_save")

      {:noreply,
       socket
       |> push_event("js-exec", %{
         to: "#confirm-modal",
         attr: "data-show-drawer"
       })}

Liveview load on layout

<div class="flex items-center gap-4 font-semibold leading-6 text-zinc-900">
      <%= live_render(@socket, PhoenixDemoWeb.Layouts.Components.CartLiveView, id: :cart_liveview) %>
    </div>

Live Component load

defmodule PhoenixDemoWeb.Layouts.Components.CartLiveView do
  use PhoenixDemoWeb, :live_view

  alias PhoenixDemoWeb.PutCartCookie
  alias PhoenixDemo.Carts

  @impl true
  def mount(_params, session, socket) do
    # Load cart
    cart_id = session[PutCartCookie.cart_id_cookie_name()]
    cart = Carts.get_cart_with_products(cart_id)
    socket = assign(socket, cart: cart)

    {:ok, socket}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <.live_component
      module={PhoenixDemoWeb.Layouts.Components.CartModal}
      id="cart_modal"
      cart={@cart}
    />
    """
  end
end

Any ideas? Does what I’m doing even make sense?

Marked As Solved

JohnnyCurran

JohnnyCurran

You should be using Phoenix.PubSub to communicate between processes – Phoenix.PubSub — Phoenix.PubSub v2.2.0

The LiveView you want should subscribe to a topic and then any other process can broadcast messages to said topic

Don’t try to find the pid of a process, that’ll only cause pain.

Also Liked

dvartic

dvartic

So I implemented a PubSub system using Phoenix.Channels. Works really well. I don’t have users implemented right now, but if I did, it would even sync the cart between the same user on different computers, which is extremely cool.

I have doubts about wether to use PubSub directly or Channels, Channels added a bit of a layer, essentially it’s the same thing as far as I can tell, so I used that.

Leaving some snippets here in case it’s helpful to someone. In terms of code it is extremely simple:

  1. Subscribe to the channel in the Cart element, which will be receiving messages. A channel can be specific to a user, multiple users or all users, in my case, every user has it’s own channel determined by the cart_id. If all shared the same channel, you can use @topic "channel_name" and then reference it as your channel name in the component.

Handle each message in handle_info, I chose to pass the complete cart but you can do anything.

  @impl true
  def mount(_params, session, socket) do
    cart_id = session[PutCartCookie.cart_id_cookie_name()]

    # Subscribe to cart channel
    PhoenixDemoWeb.Endpoint.subscribe("cart:" <> Integer.to_string(cart_id))

    # Load cart
    cart = Carts.get_cart_with_products(cart_id)
    socket = assign(socket, cart: cart)

    {:ok, socket}
  end

  @impl true
  def handle_info(msg, socket) do
    {:noreply, assign(socket, cart: msg.payload.cart)}
  end
  1. Send data from somewhere else, in my case, when adding product to the cart in the product page:
      new_cart = Carts.add_to_cart(cart_id, product_id, properties_enc)

      PhoenixDemoWeb.Endpoint.broadcast_from(
        self(),
        "cart:" <> Integer.to_string(cart_id),
        "add_to_cart",
        %{
          cart: new_cart
        }
      )

And that is it.

Where Next?

Popular in Questions Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31013 112
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement