Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply CSS class on element if current page in Phoenix

I am currently looking to add a CSS class if a page is active. What is the best way to do this in Phoenix currently? Is there a helper for this case?

def active(option, conn) do
  if option == conn.request_path do
    " class=\"active\""
  else
    ""
  end
end

In the template:

<%= "contact" |> active(@conn) |> raw %>
like image 681
rockerBOO Avatar asked Jul 22 '15 19:07

rockerBOO


People also ask

How do you assign a class to an element in CSS?

To select elements with a specific class, write a period (.) character, followed by the name of the class. You can also specify that only specific HTML elements should be affected by a class. To do this, start with the element name, then write the period (.)

How do you apply a class style rule to an element?

If you want to use a class, use a full stop (.) followed by the class name in a style block. Next, use a bracket called a declaration block that contains the property to stylize the element, such as text color or text size. CSS Classes will help you stylize HTML elements quickly.

Can we add class from CSS?

Yes you can - first capture the event using onmouseover , then set the class name using Element. className . If you like to add or remove classes - use the more convenient Element. classList method.


2 Answers

We'll use conn.path_info which returns the current path as a list of strings instead of conn.request_path. We could use that to get in our active_class helper.

def active_class(conn, path) do
  current_path = Path.join(["/" | conn.path_info])
  if path == current_path do
    "active"
  else
    nil
  end
end

Then we use it like:

<%= link "Users", to: user_path(@conn, :index), class: active_class(@conn, user_path(@conn, :index))%>

Note that we user_path/2 twice above. We could DRY that up with another helper:

def active_link(conn, text, opts) do
  class = [opts[:class], active_class(conn, opts[:to])]
          |> Enum.filter(& &1) 
          |> Enum.join(" ")
  opts = opts
         |> Keyword.put(:class, class)
  link(text, opts)
end

Why use conn.path_info instead of conn.request_path? This is because conn.request_path will return the exact path the user requested. If user visits path /foo/, then conn.request_path will return /foo/. The problem with that is the router helper we will compare to will always return a path /foo without the trailing /.

Hope that helps! Let me know if anything is unclear.

like image 97
Gjaldon Avatar answered Sep 20 '22 06:09

Gjaldon


I have created a helper for this that looks like:

defmodule LinkHelper
  @doc """
  Calls `active_link/3` with a class of "active"
  """
  def active_link(conn, controllers) do
    active_link(conn, controllers, "active")
  end

  @doc """
  Returns the string in the 3rd argument if the expected controller
  matches the Phoenix controller that is extracted from conn. If no 3rd
  argument is passed in then it defaults to "active".

  The 2nd argument can also be an array of controllers that should
  return the active class.
  """
  def active_link(conn, controllers, class) when is_list(controllers) do
    if Enum.member?(controllers, Phoenix.Controller.controller_module(conn)) do
      class
    else
      ""
    end
  end

  def active_link(conn, controller, class) do
    active_link(conn, [controller], class)
  end
end

I then import this in the def view function inside of web/web.ex

def view do
  ...
  import LinkHelper
  ...
end

Usage:

<li class="<%= active_link(@conn, PageController)%>"><a href="<%= page_path(@conn, :index) %>">Home</a></li>
<li class="<%= active_link(@conn, [FooController, BarController])%>"><a href="<%= foo_path(@conn, :index) %>">Foo or Bar</a></li>
like image 24
Gazler Avatar answered Sep 22 '22 06:09

Gazler