Default content for optional named slot

Hello,

I’m building a live component for map, and would like to use named slots for map controls such as zoom.

I would like my component to render a default markup for those controls, while letting the end user override them through named slot. However, I’m not sure how to approach it from my component.

The document for Named Slot only suggests using empty list for the slot, i.e. assign_new(socket, :zoom_in, fn -> [] end).

Is there a way to define some markup in there instead of just an empty list? From the source code, each slot is a list of maps, which a required inner_block key as a function. I don’t think I want to go into such internal details just to define a default template for the slot.

Right now, my workaround is to check the length of the assign of that slot, and render my default markup when it’s 0. Is there a better way?

My workaround

<g>
  <%= if length(@zoom_in) > 0 do %>
    <%= render_slot(@zoom_in) %>
  <% else %>
    <g>
      <path d="M0 0h24v24H0V0z" fill="none"/>
      <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
    </g>
  <% end %>
</g>

I would do it like you do now, except set the default value of zoom_in to nil and check it like

<%= if @zoom_in do %>
  <%= render_slot(@zoom_in) %>
<% else %>
  ...
<% end %>
1 Like

Small thing, @zoom_in != [] can be way faster than length(@zoom_in) > 0.

9 Likes

Thanks! I guess that’s the way to do. Was hoping for a cleaner way, like the actual slot system from web component.

Why is that the case?

1 Like

I think that != [] fails immediately while comparing to lenght means skipping through the entire linked list.


I think I read something similar in 97 Things Every Programmer Should Know. One of the stories was about a teller system that had begun grinding to a halt when being used. The issue had been that a for loop was calling string.length() after each iteration to know if it should exit the loop. The string was long and that one loop froze the entire system. Saving the length before the loop and reusing that integer cleared everything up.

Moral of the story: don’t do more work than you have to. And if you have to do a lot of work, don’t do it twice if you have a choice

2 Likes

Lists in Erlang and Elixir do not store the length in itself, so length(@zoom_in) has to count elements in @zoom_in, which is O(n), while @zoom_in != [] only needs to see if @zoom_in contains at least one element, and returns false if it does, or true if it doesn’t.

2 Likes

Worth the reading (length vs size): Naming conventions — Elixir v1.16.0

3 Likes