Tutorial

Improving LiveView UX with Phoenix Channels - Tagging part 3

This post was updated 01 May - 2020

formsphoenixliveviewtaggingchannels
In the [previous tutorial](https://fullstackphoenix.com/tutorials/tagging-interface-with-phoenix-liveview-and-tailwind-tagging-part-2) 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](https://fullstackphoenix.com/tutorials/send-events-from-js-to-a-liveview-component) 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](https://fullstackphoenix.com/tutorials/phoenix-liveview-and-invalid-csrf-token)

### 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](https://fullstackphoenix.com/tutorials/phoenix-liveview-and-invalid-csrf-token).

  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

![](https://res.cloudinary.com/dwvh1fhcg/image/upload/v1581609455/tutorials/tut_16_img_1.gif)

Related Tutorials

Published 13 Feb - 2020
Updated 01 May - 2020

Tagging interface with Phoenix LiveView and Tailwind - Tagging part 2

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
Updated 01 May - 2020

Nested model forms with Phoenix LiveView

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 ..