Tags All Entries

LiveView

LiveView uses WebSockets to update parts of a webpage with server side rendered HTML. There is a piece of client side javascript for dealing with the web sockets and events, but it does not require large amounts of customization or wrangling.

On the server side a LiveView process in an elixir module with three pieces:

  • mount: set initial state
  • handle_event: handle a change event
  • render: render a new view

Changes on the server can be pushed to multiple applications.

On the Elixir side, the Socket contains an assigns map where the state is stored.

  • you can change the state by using assign and update

Cycle 1:

  1. Intiall HTTP Request
  2. Mount & Render -> HTTP Response
  3. Javascript loaded, web socket connection to backend -> Stateful liveview process
  4. LiveView process returns static portion of template and dynamic portion of the template
  5. On Change events, the dynamic portions and re-evaluated index positions are returned each time
  6. Change events that do not actually change state does not return any new dynamic values

Templates:

  • root: Wrapping template, inner content on this template is replaced by:
    • app: non- live view template
    • live: live template -> inner content will be render by the live view component

The nesting of the templates and will be matched by the rendered content nesting of the layout and components

Enable debugging: In browser console type liveSocket.enableDebug() this will enable debugging for the duration of the browser session

By adding phx-change to a form, you can bind input values and respond to their changes.

You can think of a live view process as a process that receives events as messages and updates its state and then re renders.

handle_info is used to respond to events on the process that generated internally

phx-submit is used to have an event that happens on form submission.

You can get async handling by sending a message to the process itself. You can then respond to the front end event, while running your async handling. For example:

# Front end search event
def handle_event("zip-search", %{"zip" => zip}, socket) do
  # send message to self for longer run process
  send(self(), {:run_zip_search, zip})

  # respond back to the front end that loading is happening
  {:noreply, assign(socket, zip: zip, stores: [] loading: true)}
end


def handle_info({:run_zip_search, zip}, socket) do
   # Run the search and turn loading off
   socket = assign(socket, zip: zip, stores: Stores.search_by_zip(zip), loading: false)
   {:noreply, socket}
end

Setting flash message in a function

case Stores.search_by_zip(zip) do
    [] ->
      socket =
        socket
        |> put_flash(:info, "No Stores matching: \"#{zip}\"")
        |> assign(stores: [], loading: false)
      {:noreply, socket}
    stores ->
      socket = assign(socket, zip: zip, stores: stores, loading: false)
      {:noreply, socket}
end

References

Links to this note