View Source LiveModel (live_model v0.1.0)
Create and manage a LiveView model. A model allows you to define your LiveView assigns declaratively, similar to how
you would use a Phoenix.Component
and its attr/2,3
macro.
To create a model, import this module and use the defmodel
macro, like so:
defmodule MyAppWeb.MyLive.Model do
import LiveModel
defmodel do
field :user, MyApp.User.t(), required: true
field :grocery_list, [MyApp.Food.t()], default: []
field :sale_text, String.t() # defaults to `nil`
end
end
Then, in your LiveView module:
defmodule MyAppWeb.MyLive do
use MyAppWeb, :live_view
alias MyAppWeb.MyLive.Model
# un-import `assign/2,3` and friends that are included in
# `use MyAppWeb, :live_view` to avoid accidental use.
# (You should use the model helper functions instead, explained
# later in this moduledoc)
import Phoenix.Component, except: [assign: 2, assign: 3, assign_new: 3, update: 3]
# alternatively, if you don't use other functions in
# `Phoenix.Component` and you get an "unused import" warning
# from the above, you can do something like this instead:
# import Phoenix.Component, only: []
@impl true
def mount(_params, %{"user_id" => user_id}, socket) do
user = MyApp.get_user!(user_id)
{:ok, Model.assign_new(socket, user)} # assigns a new model struct under the `@model` assign
end
@impl true
def handle_event("new_sale", _params, sockt) do
# update assigns with `Model.put/2,3` and `Model.update/3`
{:noreply, Model.put(socket, :sale_text, "Apples are now 10% off!")}
end
@impl true
def handle_event("some_event", _params, sockt) do
# Dialyzer will warn you when trying to put/update invalid keys
{:noreply, Model.put(socket, :bad_key, :uhoh)}
end
You would then access assigns in your render function/template via @model.assign
, instead of @assign
.
The defmodel
macro will create a struct and t()
type for you. It will also create the following helper functions:
new/x
: creates a struct, where arityx
is the number of required fields plus1
. Required fields are passed as individual arguments tonew/x
, and optional fields are passed in a Keyword list (or another Enumerable like a map)assign_new/x
: similar tonew/x
, but takes the socket as the first argument and assigns the new struct under@model
.put/2-3
: given a LiveView socket, updates the:model
assign with the given field(s) and value(s). This function is meant to replace use ofPhoenix.Component.assign
in your LiveViewupdate/2-3
: given a LiveView socket, updates the:model
assign by passing the current value underfield
to the givenupdater
function. The result then replaces the original value. This function is meant to replace use ofPhoenix.Component.update
in your LiveView
Please read each function's documentation for more information.
Much of the implementation of defmodel
is heavily inspired by Lucas San Román's typedstruct
macro. You can read
more about it (and Elixir's AST/macros in general) in their
blogpost.
The "model" naming scheme is inspired by the Elm architecture/programming language.
Summary
Functions
Define a LiveView model.
Functions
Define a LiveView model.
This macro should be given a do block, whose contents are field
s:
defmodel do
field :my_string_assign, String.t(), default: ""
field :my_number_assign, integer(), required: true
end
See the LiveModel
documentation for more info and examples.