Fundamentals

Modifying state with events

Read time: 4 minutes

This guide is a direct continuation of the previous guide

If you hopped directly into this page it might be confusing because it is a direct continuation of the code from the previous lesson. If you want to skip the previous lesson and start straight with this one, you can clone the initial version for this lesson using the command git clone https://github.com/adopt-liveview/v2-myapp.git --branch mounts-and-assigns-done.

#Welcome to the dynamic world

In a modern front-end framework you don't want a view that shows something and is never modified again. We will learn the first way to modify state in LiveView: events.

We're going to build a simple button that reverses the current user's name. Edit the page_live.exs file to this:

defmodule MyappWeb.PageLive do
  use MyappWeb, :live_view

  def mount(_params, _session, socket) do
    socket = assign(socket, name: "Lubien")
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    Hello {@name}

    <input type="button" value="Reverse" />
    """
  end
end

We don't have anything that different to our previous code here except the button. So far just basic HTML. Let's do some magic now. Edit the input and add a handle_event as in the code below:

defmodule MyappWeb.PageLive do
  use MyappWeb, :live_view

  def mount(_params, _session, socket) do
    socket = assign(socket, name: "Lubien")
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    Hello {@name}

    <input type="button" value="Reverse" phx-click="reverse" />
    """
  end

  def handle_event("reverse", _params, socket) do
    socket = assign(socket, name: String.reverse(socket.assigns.name))
    {:noreply, socket}
  end
end

With this small modification we see the first example of reactivity in Phoenix: phx-click. When clicked, this input generates an event for your LiveView with the name you chose, in this case "reverse". Run the server one more time and see that when you click the button, your name is reverted!

#How do they work?

Let's talk about handle_event/3. This function is a callback that is only necessary if your LiveView has any event. For each event in your HTML code, you need a corresponding def handle_event("your_event", _params, socket). The three arguments that this callback receives are, respectively:

Reminder about callbacks!

Callbacks are simply functions that are executed when a certain thing happens.
  • The name of the event you defined.
  • Event parameters (we will explore more in another lesson, at the moment we are just ignoring this argument).
  • The state of the Socket for the current user.

Just like the mount/3 callback you receive the socket so you can modify it however you want. The expected return of the function is {:noreply, socket}.

:ok or :noreply?

You must be wondering why in the callback mount/3 we returned {:ok, socket} while in handle_event/3 we used {:noreply, socket}.

The mount/3 is just a function that LiveView executes while it's preparing its view, so it follows the Elixir pattern of saying "everything is OK, here's the initial socket".

But handle_event/3 internally uses an Erlang/Elixir standard called GenServer ("Generic Server") and in the future we will see that we can also return a value for the element that generated the event with {:reply, map(), socket}!

#Recap!

  • By adding phx-click="event_name" to an element, you trigger an event named "event_name" when it is clicked.
  • For each event in your HTML, you need an equivalent handle_event("event_name", _params, socket) callback.
  • The mount/3 callback returns {:ok, socket} while the handle_event/3 returns {:noreply, socket}.

Feedback

Got any feedback about this page? Let us know!