larshei

larshei

Structuring a live view project with proper navigation

How would you recommend structuring slightly more complex page layouts?
Ive been roaming the elixir forums for a bit, but I cant really decide on how to continue.
There was an example for a page layout like this, but id did not help me :frowning:

Goal

what i would like to achieve is:

----------------------------------------
|               top_menu               |
----------------------------------------
|      |                               |
| side |                               |
| nav  |            main               |
|      |                               |
|      |                               |

Where the top_menu allows navigation between different categories (e.g. ‘profile’, ‘timeline’, ‘messages’, …). It does not need to change between pages.

So if a user selected e.g. ‘messages’, a side_nav specific to messages should be printed that contains a list of chat partners. The main area then displays the content of whatever chat was selected in side_nav.

What I tried

I was able to build a setup like this doing the following:

  • add the top_menu to the live.html.leex template.
  • each menu entry does a live_redirect.
  • live views load the side_nav as a component. Each item in the nav does a live_patch with different live_actions.
  • live views load a component to main, depending on the live action.

This way, I get

  • the page layout I wanted
  • one live view per item in the top_menu that i can store in a separate folder with all its components
  • All routes are visible in the router and the url is updated properly

The Problem

The top menu should have a sign in/out button, depending on wether a user is signed in or not.
It seems I cannot get that information in the live.html.leex template. To get this information, I need access to the session and therefore a live view.

My first approach was to put the top_menu into a separate component and render it in every live view.
However, this introduces duplication, cause I will have to determine wether a user is signed in or not separately on every live view.

The second thought, that I cant quite wrap my head around, is to use a live view for the top_menu and then another live view for side_nav + main. That way, I only need to check the login state on the first live view.

Question

How would you structure a page that has a top menu with login/out button?

I cannot really see how the setup with a parent and multiple child live views would be achieved. Could you maybe help me here by pointing me to an example?

Do any of my approaches or thoughts make sense or am I way off the track?

Marked As Solved

larshei

larshei

Turns out nesting multiple views is not very convenient, as some functions (e.g. handle_params) are not available on child views. Overall, this nested structure requires a lot of data passing between different views/components.

The approach was changed to use templates.

In each live view use MyAppWeb, :live_view is used to load the template. It can be found in lib/my_app_web.ex and will load lib/my_app_web/templates/live.html.

Simply duplicate the existing live_view, rename to e.g. my_live_view.
Duplicate the live template and add the top and side menu as components. Load this template in my_live_view. Then, in your MyAppWeb.MyLive use this template with use MyAppWeb, :my_live_view.

This way, no nested live views are needed, but there is still the option for multiple side menus, by simply loading different templates.

Also Liked

chautelly

chautelly

I’m very new to this and somewhat figuring out similar questions so don’t take my ideas for granite.

  1. Create a single liveview that all routes and sub routes point to:
#router.ex
live "/", MyAppLive, :index
live "/profile", MyAppLive, :profile
live "/timeline", MyAppLive, :timeline
live "/messages", MyAppLive, :{:messages, :index}
live "/messages/:message_id", MyAppLive, {:messages, :detail}
live "/messages/:message_id/edit", MyAppLive, {:messages, :edit}
  1. In MyAppLive implement handle_params if you want to perform any side effects (mutate state, do async work, etc)
defmodule MyAppLive do
  ....
  mount (...)
  ....
  def handle_params(params, url, socket) do
    {:noreply, socket |> assigns(message_id: Map.get(params, "message_id")}
  end
  1. In your template or render function return based on socket.assigns.live_action (or custom state updates).
# my_app_live.html.leex
<nav>
<%=
   case @live_action do
      :profile -> live_render(@socket, SideNavProfile, id: @live_action
      ...
%>
<nav>
<section>
<%=
   case @live_action do
      :profile -> live_render(@socket, ProfileLive, id: @live_action
      {:messages, message_action} -> live_render(
          @socket,
          MessagesLive,
          id: "messages-#{@message_id},
          session: {"message_id" => @message_id, "action" => message_action})
      ...
%>
</section>

In MessagesLive’s mount you’ll have access to session.message_id and session.message_action which you can assign to it’s own assign and in it’s template render based on message_action, etc.

MyAppLive can also keep track of the signed in user and send that to a LiveComponent or LiveView at the top of your template. I would probably use a component rather than a view for the top bar.

Again, this is where I’m at with my understanding so far. I wouldn’t mind if someone with much more liveview experience has any pointers.

larshei

larshei

For Anyone who ends up reading this in the future, there is more on the same topic to be found here: LiveView with complex layouts - #10 by 50kudos

chautelly

chautelly

Yeah I just finished refactoring my app like this. I think this is the best way forward. I was worried the navigation would flicker since it would be rendered in different liveview processes but it’s working great so far.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement