Data

Stateful components like Surface.LiveView and Surface.LiveComponent hold their state in the socket's assigns. In Surface, those assigns are called data assigns.

In order to declare a data assign, you must use the data macro:

data name, type, options

Where:

  • name - is the name of the assign.
  • type - an atom defining the type of the assign. See all available types in section "Properties > Property types".
  • options - a keyword list of options for additional customization.

Supported options

  • default - defines a default value for the assign.
  • values - the list of possible values for the assign.

In the following example, we create a simple Counter component that has its state defined by a single assign named count. You can use the - and + buttons to decrement/increment the counter's value.

Note: The data macro is available in both stateful and stateless components. It allows you to define intermediary assigns in the update function of the component that computes values based on one or several properties.

0

defmodule Counter do
  use Surface.LiveComponent

  data count, :integer, default: 0

  def render(assigns) do
    ~H"""
    <div>
      <h1 class="title">
        {{ @count }}
      </h1>
      <div>
        <button class="button is-info" :on-click="dec">
          -
        </button>
        <button class="button is-info" :on-click="inc">
          +
        </button>
      </div>
    </div>
    """
  end

  def handle_event("inc", _value, socket) do
    {:noreply, update(socket, :count, &(&1 + 1))}
  end

  def handle_event("dec", _value, socket) do
    {:noreply, update(socket, :count, &(&1 - 1))}
  end
end

Note: Since we defined a default value for count, we don't need to implement the mount/1 callback to initialize it. All data assigns with default values will be automatically initialized by Surface. That means if you need some data to be initialized, you need to add a default value, even if it's nil. If you do not add a default value, the data is not initialized.