Wrapping LiveView render calls in a macro

I’m trying to define a macro to dynamically create render/1 calls in my LiveView and having some trouble.

I did find this but mine includes calling live_component within the sigil which is what seems to be causing the problem.

What I’m trying to do is this:

defmodule MyAppWeb.Macros do
  defmacro defrender(component, slug, id) do
    quote do
      @impl true
      def render(%{slug: unquote(slug)} = var!(assigns)) do
        ~H"""
        <%= live_component unquote(component), id: unquote(id) %>
        """
      end
    end
  end
end

…and then in my LiveView:

defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view

  import MyAppWeb.Macros

  # def mounts, updates, handle_events, etc....

  defrender(MyAppWeb.Blog, "blog", "blog")
end

I end up with a compile error: unquote called outside quote.

I’ve tried various uses and combos of var! and unquote! inside the render function, but my mental model here is still very weak. I sort of understand that I have a macro within a macro here, but it’s making my brain explode.

The stakes are low here, of course. I’m mostly trying to figure this out for learning purposes.

Thanks!

1 Like

I believe the immediate problem is you are not using quote in your macro definition.

defmodule MyAppWeb.Macros do
  defmacro defrender(component, slug, id) do
    quote do
      @impl true
      def render(%{slug: unquote(slug)} = var!(assigns)) do  
        ~H"""
        <%= live_component unquote(component), id: unquote(id) %>
        """
      end
    end
  end
end

I suspect you will also want to pin (^) the unquoting of slug, depending on what you are passing it. But not totally sure on that.

also some string interpolation probably needs to happen in your ~H sigil for the unquote(id)

Oops! That was actually just a typo on my part—I retyped the whole thing to change some names instead of just changing the names (why did I do this? I dunno, haha). I edited my question to reflect this.

I’ll try out your other suggestions and report back. Thank you for the response!!

1 Like

In some way try to send the arguments one level up, in order words, do not send them in the macro signature, instead maybe in the mount (in the assigns?). Then in the macro definition inside the ~H sigil use something like:

  ~H"""
   <%= live_component @component, id: @id %>
  """

Doing that the unquote called outside quote should go away. I was working in something similar to your case and getting the same error like you. I did what I mentioned before and it worked. Hope it helps @sodapopcan.

Reference: Assigns and HEEx templates — Phoenix LiveView v0.16.4