Tutorial

View on Github

Improving LiveView UX with Phoenix Channels - Tagging part 3

This post was updated 01 May - 2020

channelsformsliveviewphoenixtagging

In the previous tutorial I set up the tagging interface. It had however a small issue. If I added a tag, it didnt really refocus on the input so I needed to manually set the mouse there again.

In this tutorial, I will show how I can broadcast a message using Phoenix Channels to be handled by channels javascript and then simply set focus using javascript.

This tutorial also builds upon this turorial where I set up an AppChannel that uses a channel name that is concatinated like:

"app:#{csrf_token}"

And to pass in the csrf_token into the session so I can use it in all LiveView components is covered in this tutorial

STEP 1 - LiveView component changes

I basically need to do 3 changes here.

  1. In the mount function, extract csrf_token from session and add a channel_name to assigns
  2. Add a refocus_input/1 function where I actually to the broadcast from
  3. Call refocus_input/1 when a tag is added

Start in the mount function. Note that the csrf_token comes from a plug that I set up in a previous tutorial.

  def mount(%{"id" => product_id, "csrf_token" => csrf_token} = _session, socket) do
    product = get_product(product_id, connected?(socket))

    assigns = [
      ...
      # CHANNEL NAME
      channel_name: "app:#{csrf_token}",
      ...
    ]

    {:ok, assign(socket, assigns)}
  end

Next step is to add the function where I do the actual broadcast from. Note that I specify the id of the input field. And the event name is "focus". So in theory, I could use the same JS for different focus events that should focus on different dom elements.

  defp refocus_input(socket) do
    TutorialWeb.Endpoint.broadcast_from(
      self(),
      socket.assigns.channel_name,
      "focus",
      %{id: "tagging-form"}
    )
    socket
  end

Last part there is to add refocus_input(socket)

  def handle_event("pick", %{"name" => search_phrase}, socket) do
    product = socket.assigns.product
    taggings = add_tagging_to_product(product, search_phrase)
    refocus_input(socket)
    ...
  end

STEP 2 - Frontend changes

I basically just need to do 2 things.

  1. Add an id to the input field
  2. Add a channel callback in JS

So open the template and add id="tagging-form" inside the input.

# lib/tutorial_web/templates/product/product_tagging.html.leex

<%= form_tag "#", [phx_change: :search, phx_submit: :submit] do %>
  ...
  <input
    type="text"
    id="tagging-form"
    class="inline-block text-sm focus:outline-none"
    name="search_phrase"
    value="<%= @search_phrase %>"
    phx-debounce="500"
    placeholder="Add tag"
  >
  ...
<% end %>

And open the socket.js and add

// assets/js/socket.js

channel.on("focus", msg => {
  const elm = document.getElementById(msg['id'])
  elm.focus()
  elm.value = ''
})

Final result

Phoenix Boilerplate

Generate a Phoenix Boilerplate and save hours on your next project.

Try now

SAAS Starter Kit

Get started and save time and resources by using the SAAS Starter Kit built with Phoenix and LiveView.

Learn More

Related Tutorials

Published 13 Feb - 2020

Tagging interface with Phoenix LiveView and Tailwind - Tagging part 2

formsliveviewphoenixtaggingtailwindtypeahead

In the previous tutorial, I set up the the backend for being able to add tags to products. I have also written a tutorial about adding a LiveView an..

Published 05 Feb - 2020

Nested model forms with Phoenix LiveView

formsliveviewphoenix

I my last article, I set up a relationship between products and variants. But what I didn't go through was to setup a form where you can manage the ..