Navigation

Your second LiveView

Read time: 5 minutes

This guide is a direct continuation of the previous guide

If you hopped directly into this page, it might be confusing because it is a direct continuation of the code from the previous lesson. If you want to skip the previous lesson and start straight with this one, you can clone the initial version for this lesson using the command git clone https://github.com/adopt-liveview/v2-myapp.git --branch events-done.

All this time we were working with just a single LiveView called PageLive. Today we are gonna change that.

#Getting to know Phoenix.Router

Every Phoenix application, without exception, requires a Router. When you create a new Phoenix project, it already generates this file with the name YourProject.Router. Open lib/myapp_web/router.ex:

defmodule MyappWeb.Router do
  use MyappWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {MyappWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", MyappWeb do
    pipe_through :browser

    live "/", PageLive, :home
  end

  # Other scopes may use custom stacks.
  # scope "/api", MyappWeb do
  #   pipe_through :api
  # end

  # Enable LiveDashboard and Swoosh mailbox preview in development
  if Application.compile_env(:myapp, :dev_routes) do
    # If you want to use the LiveDashboard in production, you should put
    # it behind authentication and allow only admins to access it.
    # If your application does not have an admins-only section yet,
    # you can use Plug.BasicAuth to set up some basic authentication
    # as long as you are also using SSL (which you should anyway).
    import Phoenix.LiveDashboard.Router

    scope "/dev" do
      pipe_through :browser

      live_dashboard "/dashboard", metrics: MyappWeb.Telemetry
      forward "/mailbox", Plug.Swoosh.MailboxPreview
    end
  end
end

#Anatomy of a router module

#The use macro

Phoenix will always add to router modules something like use MyappWeb, :router. Behind the scenes, it imports router functions like get/4, post/4 and live/4 so you can define routes.

#Pipelines

Think of pipelines as reusable router settings for multiple route groups. At this point, all you need to care about is that the :browser pipeline works, well, on browsers. They're used inside scope blocks like pipe_through :pipeline_name.

#Dev routes

Using if Application.compile_env(:myapp, :dev_routes) do we can ensure routes are only compiled in development environments and skip prod altogether. This is useful for our fake Mailbox to test mailing without setting SMTP or APIs, plus our Live Dashboard route. Got curious? Open http://localhost:4000/dev/dashboard

#Scope block

scope/4 blocks are often used to group routes that have similar requirements. You'd often see in Phoenix projects a scope for unauthenticated routes, another one for authenticated routes, and one or more scopes for API routes. Later on, we will be seeing those in more depth.

#Adding our second LiveView

Using the live/4 macro, we define that on the home page ("/") the PageLive module will be rendered and its Live Action will be :index. Don't need to worry about Live Action; we will go back to it in future lessons.

Edit router.ex to add a second route like this:

...
scope "/" do
  pipe_through :browser

  live "/", PageLive, :home
  live "/other", OtherPageLive, :other
end
...

Then create a file under lib/myapp_web/live/other_live.ex:

defmodule MyappWeb.OtherPageLive do
  use MyappWeb, :live_view

  def render(assigns) do
    ~H"""
    <h1>OtherPageLive</h1>
    <.link navigate={~p"/"}>Go to home</.link>
    """
  end
end

And finally edit your PageLive like this:

defmodule MyappWeb.PageLive do
  use MyappWeb, :live_view

  def render(assigns) do
    ~H"""
    <h1>PageLive</h1>
    <.link navigate={~p"/other"}>Go to other</.link>
    """
  end
end

The OtherPageLive is very similar to the first one. We only changed the main text and the navigation button text.

The new things here are: the <.link> component and the sigil_p.

This is the first time in this course that you've seen an HTML tag that starts with .. These tags are known as components; we will talk about them in detail in the future.

The important thing about the .link component is that it is specialized in providing navigation between pages on your Phoenix website. Using the navigate={...} attribute, Phoenix can make an optimized transition between two LiveViews whenever possible, so always prefer this component instead of using the <a> HTML tag.

#Verified Phoenix Routes

In Phoenix projects, whenever you want to write a route you could very well use a string like "/path/to/page". What if this route doesn't exist? We would only know when we click this link and see the issue.

To avoid surprises with routes that don't exist, Phoenix comes with a feature called Verified Routes in which you use the sigil_p in the format ~p"/path/to/page/" and Phoenix will warn you if you are using routes that don't exist.

#Recap!

  • Every Phoenix application has a Router.
  • Routers will use pipelines and scope blocks to define how certain routes behave.
  • On a Router we can define LiveView routes using the live/4 macro.
  • HTML tags with . at the beginning such as <.link> indicate that this tag is actually a component.
  • We must use the <.link navigate={~p"/route"}> component in our LiveViews to navigate efficiently between routes.
  • Using sigil_p, we can write routes so that Phoenix will warn us if they don't exist, so we can detect problems at development time.

Feedback

Got any feedback about this page? Let us know!