Phoenix component wrapped in an if block not updating

I have a component rendered in my root.html.heex layout. It doesn’t update as I navigate through live routes. I have to refresh my browser to get it to pick up changes. I’m debugging inside my component, so I know that’s it not even being called the other times.

<%= if assigns[:favicon] do %>
  <IdoWeb.EmojiComponents.favicon emoji={@favicon}/>
<% end %>

The @favicon assign is being set / changed as I navigate, but the .favicon component isn’t added/removed/updated. What am I missing?

Thanks!

Assigns should be referenced with the @, not as plain variables. Otherwise change tracking breaks.

<%= if @favicon do %>
  <IdoWeb.EmojiComponents.favicon emoji={@favicon}/>
<% end %>

Edit: sorry, didn’t click that this is the root. See other thread below.

Note also that this will raise if the assign isn’t set. You should make sure to set a nil default, preferably using the new attr if you’re on LiveView 0.18:

attr :favicon, :string, default nil

def my_component(assigns) do
  …
end

If you are using an earlier version, you can do

def my_component(assigns) do
  assigns =
    assigns
    |> assign_new(:favicon, fn -> nil end)

  …
end

I added my component right below the standard page title, which works fine without using the @:

<.live_title suffix=" · Phoenix Framework">
  <%= assigns[:page_title] || "Ido" %>
</.live_title>

Why does it work with assigns, but mine doesn’t?

Assigning a default in my component still fails. Just referencing the @favicon from heex causes an error. And I can’t just assign a nil value as a default higher up, because this is in my root layout- I’d have to assign a value for every single live view in the future. I thought this is why the root layout is using assigns[:page_title] rather than @page_title. And it updates properly for it.

Note: if I try to pass favicon (or even page_title) as an attribute, the component has the same issue- it’s never called to re-render:

<IdoWeb.EmojiComponents.favicon emoji={assigns[:favicon]}/>

Is there a special scenario that values passed in slots will always re-render?

<.live_title suffix=" · Phoenix Framework">
  <%= assigns[:page_title] || "Ido" %>
</.live_title>

I may be asking the wrong question. Is it possible to add/remove/modify things in the HTML <head> tag with liveview? It works for the slot of the .live_title component, but is that a special case that Phoenix knows how to update over the wire?

I think you’re onto something here. I’m heading off to bed, but yes: LiveViews are (to my knowledge) somewhat “scoped” to the root at which they’re rendered, whereas .live_title is a sort of “special case” that is available by default because it is a common use-case.

This does not mean that what you’re trying to accomplish isn’t possible, but it may mean a bit of extra boilerplate to get it all working.

It is explained here: Feature Request: LiveView Dynamic Favicon

Yep, that’s it. I’m surprised to see this isn’t supported out of the box.

phoenix_live_favicon may do exactly what I need, though it has version conflicts with my current setup so I’ll have to punt now.

Thank you both!