How to pass options to LiveView __using__ for Phoenix > v1.6

Hello everyone,

I would like to customize the container that LiveVIew wraps with and for that, I need to pass the container option to the LiveView __using__ but I can’t find any examples of how to do that in Phoenix > v1.6. In the forum I see the following example:

use Phoenix.LiveView,
  namespace: MyAppWeb,
  container: {:tr, class: "colorized"},
  layout: {MyAppWeb.LayoutView, :app},
  log: :info

But I am using LiveView like this:

use MyAppWeb, :live_view

I tried the following but none of them worked:

use MyAppWeb, :live_view, container: {:tr, class: "colorized"}
use MyAppWeb, [:live_view, container: {:tr, class: "colorized"}]
use MyAppWeb, {:live_view, container: {:tr, class: "colorized"}}

You want to edit myapp_web.ex (replace myapp with your own app name).

In there, there is a function def live_view do, which has the call to use Phoenix.LiveView.

To really understand whats going on you need to check the elixir documentation on use, apply and peep the function __using__ at the bottom of myapp_web.ex.

When you call use MyAppWeb, :live_view, you’re effectively inserting the code in the live_view function into your module, so you have a few options:

  1. Add a second function with different options and “use” that instead, eg:
# or you could just change live_view if you *always* want to use these options
def admin_live_view do
  quote do
    use Phoenix.LiveView, layout: {Admin.Layouts, :app}, container: {:tr, class: "colorised"}
    # and whatever else (see default live_view function) ...
  end
end

use MyAppWeb, :admin_live_view
  1. Update the live_view function to accept arguments and quote them out into the use Phoenix.LiveView call, and update __using__ to accept arguments and pass them down. This gets a bit complicated as you need to handle with-option and without-option, defaults, etc.

I would go with option 1 at first. You either want all your views to use some common container options (so update live_view with different defaults), or only some (so add a new table_live_view etc function). If you find you are always wanting different options for different views then it might be worth doing option 2.

1 Like

That’s exactly what I was looking for. Thank you a lot for the help!

I also tried to implement the second option but without any luck. I managed to modify the live_view function to accept arguments but I can’t make __using__ accept arguments. I am breaking my head now on how to do it. I checked the __using__ of Phoenix.LiveView which accepts arguments but I still don’t understand how does it do it.

What modifications do I need to do to the __using__ of MyAppWeb for it to accept arguments like this:

use MyAppWeb, :live_view, container: {:tr, class: "colorized"}

No matter what I do I always get

** (CompileError) undefined function use/3

As the error states this is calling use/2 as in use(MyAppWeb, :live_view, [container: {:tr, class: "colorized"}]). There is no use/3 and also no __using__/2. You only a use/2 and __using__/1, which means you need to pass a single optional parameter after the module with use/2. You cannot add arbitraray additional parameters.

In your case that means wrapping what is currently two pieces of information into a container. Could be a list, could be a tuple. You could make the type part of the keyword list.

I tried already with wrapping and it works but I want to understand how the Phoenix.LiveView module accepts multiple arguments in its __using__:

use Phoenix.LiveView,
  namespace: MyAppWeb,
  container: {:tr, class: "colorized"},
  layout: {MyAppWeb.LayoutView, :app},
  log: :info

That’s not multiple arguments, that’s a single keyword list, without the square brackets, which are optional when the keyword list is the last parameter of a call.

use Phoenix.LiveView,
  [
    namespace: MyAppWeb,
    container: {:tr, class: "colorized"},
    layout: {MyAppWeb.LayoutView, :app},
    log: :info
  ]
1 Like

:exploding_head: Wow now it all makes sense. Didn’t know that the square brackets can be omitted. Thanks a lot for your answer.