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
endThen, 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)}
endYou 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 arityxis 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:modelassign with the given field(s) and value(s). This function is meant to replace use ofPhoenix.Component.assignin your LiveViewupdate/2-3: given a LiveView socket, updates the:modelassign by passing the current value underfieldto the givenupdaterfunction. The result then replaces the original value. This function is meant to replace use ofPhoenix.Component.updatein 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 fields:
defmodel do
field :my_string_assign, String.t(), default: ""
field :my_number_assign, integer(), required: true
endSee the LiveModel documentation for more info and examples.