How do i dynamically theme Phoenix views

Hello community,

I’m new to phoenix and struggling to implement a feature that would allow my users to apply a theme of their choice (e.g. animals, cars, nature).

Each of these themes has its own assets and I’m using put_layout to assign the chosen layout but struggling to render the views according to the chosen theme

My controller looks like this

defmodule Client.PageController do
  use Client, :controller
  
  def index(conn, _params) do
    theme = get_user_theme(conn)

    conn
    |> put_layout(theme)
    |> render('index.html')
  end
end 

My templates directory

templates\
 -> layouts
     - app.html.eex
     - themeA.html.eex
     - themeB.html.eex
 -> pages
     - index.html.eex
 -> themeA
     - index.html.eex
 -> themeB
     - index.html.eex

how do i dynamically choose between themeA/index.html.eex and themeB/index.html.eex without getting a template not found error

Hello and welcome,

I think it should be…

|> put_layout(theme)

as theme is your variable.

1 Like

thanks for catching the type @kokolegorille. The layout part works ok. it’s dynamically rendering the template I’m having trouble with. See the example below

defmodule Client.PageController do
  use Client, :controller
  
  def index(conn, _params) do
    theme = get_user_theme(conn)

    conn
    |> put_layout(theme)
    |> render('#{theme}/index.html')
  end
end 

If You are using PageController, You are using PageView, which will look into template/page.

Try to put themes folder inside page folder.

1 Like

@kokolegorille thanks for your answer. It set me back on track. I was able to get it to to render using by moving and renaming themeA\index.html.eex to page\themeA.index.html.

I wanted to be able to neatly put organise themes in folders and I found this topic https://elixirforum.com/t/how-to-render-a-template-inside-a-web-templates-folder-subfolder/1404/6?u=kbee and changed my view to

defmodule MyApp.PageView do
  use Phoenix.View, root: "lib/myapp/templates", pattern: "**/*"
end

and now I can do

defmodule MyApp.PageController do
  use MyApp, :controller
  
  def index(conn, _params) do
    theme = get_user_theme(conn)

    conn
    |> put_layout(theme)
    |> render('#{theme}/index.html')
  end
end 
3 Likes