Примените класс CSS к элементу, если текущая страница в Phoenix

В настоящее время я хочу добавить класс CSS, если активна страница. Каков наилучший способ сделать это сейчас в Финиксе? Есть ли помощник для этого случая?

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

В шаблоне:

<%= "contact" |> active(@conn) |> raw %>

Ответ 1

Мы будем использовать conn.path_info, который возвращает текущий путь как список строк вместо conn.request_path. Мы могли бы использовать это, чтобы попасть в наш помощник active_class.

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

Затем мы используем его как:

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

Заметим, что мы user_path/2 дважды выше. Мы могли бы сушить это с помощью другого помощника:

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

Зачем использовать conn.path_info вместо conn.request_path? Это связано с тем, что conn.request_path вернет точный путь, который запросил пользователь. Если пользователь посещает путь /foo/, то conn.request_path вернет /foo/. Проблема с этим - помощник маршрутизатора, который мы будем сравнивать, всегда будет возвращать путь /foo без конечного /.

Надеюсь, что это поможет! Дайте мне знать, если что-то неясно.

Ответ 2

Я создал для этого помощника, который выглядит так:

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

Затем я импортирую это в функцию def view внутри web/web.ex

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

Использование:

<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>