README.md

# LiveViewEvents

![Elixir CI](https://github.com/DockYard/live_view_events/actions/workflows/elixir-ci.yml/badge.svg)

LiveViewEvents provides a set of tools to send events between components.

## Installation

Add `live_view_events` to your list of dependencies in `mix.exs` like:

```elixir
def deps do
  [
    {:live_view_events, "~> 0.1.0"}
  ]
end
```

## Usage

Add `use LiveViewEvents` whenever you want to use any of the features of the libraries.

### Sending events to LiveView components

You can send events to LiveView components by using `notify_to/2` or `notify_to/3` (the only
difference being that the latter sends some extra params). These functions accept a target as
first argument and a message name as second. Targets can be any of:

  - `nil` makes the function call be a noop. Useful if you want to only send a message if an explicit target has been passed in.
  - `:self` to send to `self()`.
  - A PID.
  - A tuple of the form `{Module, "id"}` to send a message to a `LiveView.Component` in the same process.
  - A tuple of the form `{pid, Module, "id"}` to send a message to a `LiveView.Component` in a different process.

You an handle these messages on the `handle_info/2` callback on
your LiveView components. For being able to do so, you need to
use the `handle_info_or_assign/2` macro on the `update/3` callback of your component. 

## Example


In our view, we are going to have two components. The first one is a `Sender`
that can send an event to whatever is being passed. Let's dig into the
implementation:

```elixir
defmodule MyAppWeb.Components.Sender do
  use MyAppWeb, :live_component
  use LiveViewEvents

  def mount(socket) do
    socket = assign(socket, :notify_to, :self)

    {:ok, socket}
  end

  def render(assigns) do
    ~H[<button type="button" phx-click="clicked" phx-target={@myself}>Send event</button>]
  end

  def handle_event("clicked", _params, socket) do
    notify_to(socket.assigns.notify_to, :sender_event, :rand.uniform(100))
    {:noreply, socket}
  end
end
```

This component will send a `:sender_event` message to whatever we pass to the `notify_to`
attribute. It sends a random number between 0 and up to 100 as parameter.

Let's dig into the receiver:

```elixir
defmodule MyAppWeb.Components.Receiver do
  use MyAppWeb, :live_component
  use LiveViewEvents

  def mount(socket) do
    socket = assign(socket, :messages, [])

    {:ok, socket}
  end

  def update(assigns, socket) do
    socket = handle_info_or_assign(socket, assigns)

    {:ok, socket}
  end

  def render(assigns),
    do: ~H[<ul><li :for={m <- @messages}><%= m %></li></ul>]

  def handle_info({:sender_event, num}, socket) do
    {:noreply, update(socket, :messages, &[num | &1])}
  end
end
```

This component will receive messages and handle them in `handle_info/2` because
it is using `handle_info_or_assign/2` in their `LiveComponent.update/2`.
It will add the received messages to `socket.assigns.messages` and display
them. As the reader can see, it is pattern matching against `:sender_event` messages.
When `notify_to/3` is used, the message sent is a tuple containing the event name
as first element, and the params as second the second element.

Finally, let's take a look at what the live view template would need to look like
for this to work:

```heex
<div class="contents">
  <.live_component
    module={MyAppWeb.Components.Sender}
    id="sender"
    notify_to={{MyAppWeb.Components.Receiver, "receiver"}}
  />
  <.live_component module={MyAppWeb.Components.Receiver} id="receiver" />
</div>
```

In this template, we set `notify_to` to the tuple `{MyAppWeb.Components.Receiver, "receiver"}`.
The first element of the tuple is the live component module and the second is the id.
Optionally, the tuple can contain an extra first element that needs to be a PID. Though
this might not be useful in the application code (there are way better ways to send events
between processes), it is quite useful when testing. When testing a `LiveView`
it creates a new process for it. Its PID can be accessed through `view.pid`.