Der beste Weg, um "aktuelle" Klasse zu nav in Rails 3 hinzuzufügen

111

Ich habe einige statische Seiten in einem Navigationsmenü. Ich möchte dem aktuell angezeigten Element eine Klasse wie "aktuell" hinzufügen.

Ich füge dazu Tonnen von Hilfsmethoden hinzu (jeweils für einen Gegenstand), um den Controller und die Aktion zu überprüfen.

def current_root_class
  'class="current"' if controller_name == "homepage" && action_name == "index" 
end

<ul>
  <li <%= current_root_class %>><%= link_to "Home", root_path %>

Gibt es einen besseren Weg, dies zu tun? Mein aktueller Weg ist so dumm ......

PeterWong
quelle

Antworten:

56

Keine wirkliche Antwort hier, weil ich genauso benutze wie Sie. Ich habe gerade Hilfsmethoden definiert, um auf mehrere Controller oder Aktionen zu testen:

In application_helper.rb

  def controller?(*controller)
    controller.include?(params[:controller])
  end

  def action?(*action)
    action.include?(params[:action])
  end

Dann können Sie if controller?("homepage") && action?("index", "show")in Ihren Ansichten oder anderen Hilfsmethoden verwenden ...

Yannis
quelle
Ihr Weg passt am besten, wenn einige Seiten von verschiedenen Controllern / Aktionen bearbeitet werden, aber im selben Menüpunkt, oder? Haben Sie weitere Vorteile festgestellt ~?
PeterWong
Kein Vorteil mehr außer der Prägnanz der Syntax. Ich bin gespannt, ob jemand anderes eine bessere Lösung hat.
Yannis
Ich habe diese Methode mit großem Erfolg durchgeführt. Dieser Code wurde zur Ansicht hinzugefügt: <% = link_to "Users", users_path, class: (controller? ("Users")? 'Selected': nil)%> Wirklich gut, dass es sowohl für / users als auch für / users / new funktioniert .
Andreas
1
Eine Verbesserung könnte sein controller_nameund action_nameanstelle von Params wahrscheinlich
Francesco Belladonna
Gut gemacht. Ich habe nicht daran gedacht, dies einfach zu halten, aber das lässt sich sehr gut skalieren. +1
newdark-it
290

Ich habe einen Helfer namens gemacht nav_link:

def nav_link(link_text, link_path)
  class_name = current_page?(link_path) ? 'current' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

verwendet wie:

nav_link 'Home', root_path

das wird HTML wie produzieren

<li class="current"><a href="/">Home</a></li>
Skilldrick
quelle
3
Dies funktioniert gut mit twitter ootstrap , wenn Sie den Twitter Bootstrap navbar verwenden twitter.github.com/bootstrap/examples/hero.html
Lee McAlilly
41
Ändern Sie zu class_name = current_page? (Link_path)? 'current': Null, wenn Sie nicht möchten, dass das Klassen-Tag angezeigt wird, wenn es nicht auf der aktuellen Seite ist
Matthew Hui
1
Wie würden Sie dies für verschachtelte Listen ändern, die in Dropdowns verwendet werden?
Doremi
9
TROCKEN wie eine Wüste
Orlando
1
Ich habe ein paar zusätzliche Argumente extra_classes = nil, id = nil hinzugefügt, dann innerhalb des content_tag content_tag (: li, class: [Klassenname, extra_classes], id: id), damit Sie den Elementen auch Ihre eigenen Klassen und IDs hinzufügen können :)
Jon
72

Verwenden Sie den current_page?Helfer, um zu bestimmen, ob Sie die "current"Klasse zuweisen sollen oder nicht . Beispielsweise:

<%= 'active' if current_page?(home_about_path) %>

Beachten Sie, dass Sie auch einen Pfad übergeben können (nicht nur einen Hash von Optionen), z current_page?(root_path).

jpemberthy
quelle
3
Gibt es eine Möglichkeit, Abfrageparameter zu ignorieren?
Mohamad
@ Mohamad, können Sie dies tun: current_page? (Controller: 'Benutzer', Aktion: 'Index')
nilid
26

Ich verwende diese Funktion nav_link (Text, Link) in application_helper.rb (Rails 3), um die Arbeit zu erledigen, und sie rollt meine Bootstrap-Twitter 2.0-Navigationsleisten-Links für mich.

def nav_link(text, link)
    recognized = Rails.application.routes.recognize_path(link)
    if recognized[:controller] == params[:controller] && recognized[:action] == params[:action]
        content_tag(:li, :class => "active") do
            link_to( text, link)
        end
    else
        content_tag(:li) do
            link_to( text, link)
        end
    end
end

Beispiel:

<%=nav_link("About Us", about_path) %>
Peyton
quelle
Dies könnte durch die Verwendung der current_page?Methode wie in anderen Antworten vereinfacht werden .
Teemu Leisti
10

Ich habe es so gemacht, dass ich dem application_helper eine Hilfsfunktion hinzufüge

def current_class?(test_path)
  return 'current' if request.request_uri == test_path
  ''
end

Dann in der Navi,

<%= link_to 'Home', root_path, :class => current_class?(root_path) %>

Dadurch wird der Verknüpfungspfad mit der aktuellen Seiten-URL verglichen und entweder Ihre aktuelle Klasse oder eine leere Zeichenfolge zurückgegeben.

Ich habe dies nicht gründlich getestet und bin sehr neu in RoR (nach einem Jahrzehnt mit PHP). Wenn dies also einen großen Fehler aufweist, würde ich es gerne hören.

Zumindest auf diese Weise benötigen Sie nur 1 Hilfsfunktion und einen einfachen Aufruf in jedem Link.

vollgebacken
quelle
1
Nur ein Problem. Ich habe request.path anstelle von request_uri verwendet (request_uri hat nicht funktioniert, möglicherweise ein Problem mit der Rails-Version?). Ihre Antwort ist meiner Meinung nach sauber und elegant.
Tony
6

Um die Antwort von @Skilldrick auszubauen ...

Wenn Sie diesen Code zu application.js hinzufügen, wird sichergestellt, dass alle Dropdown-Menüs mit aktiven untergeordneten Elementen auch als aktiv markiert werden ...

$('.active').closest('li.dropdown').addClass('active');

So rekapitulieren Sie unterstützenden Code> Fügen Sie einen Helfer namens nav_link hinzu:

def nav_link_to(link_text, link_path)
  class_name = current_page?(link_path) ? 'active' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

verwendet wie:

nav_link_to 'Home', root_path

das wird HTML wie produzieren

<li class="active"><a href="/">Home</a></li>
TheEricMiller
quelle
4

Ich denke der beste Weg ist

application_helper.rb:

def is_active(controller, action)       
  params[:action] == action && params[:controller] == controller ? "active" : nil        
end

Und im Menü:

<li class="<%= is_active('controller', 'action') %>">
IPIvliev
quelle
Ist es in Ordnung, eine leere Klasse so zu lassen?
Harsha MV
Ja. Es mag seltsam aussehen, wenn Sie in der Quelle eine Reihe leerer Klassenattribute sehen, aber es ist gültiges HTML.
Kobaltz
Sie können verwenden <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>, es wird kein Klassenattribut für nil gedruckt. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
neonmate
4

Ich weiß, dass es eine veraltete Antwort ist, aber Sie können all diese aktuellen Seitenprüfungen leicht ignorieren, indem Sie einen Link_to-Helfer-Wrapper namens active_link_to gem verwenden. Es funktioniert genau so, wie Sie es möchten . Fügen Sie dem aktuellen Seitenlink eine aktive Klasse hinzu

fuyi
quelle
4

Hier ist das vollständige Beispiel zum Hinzufügen einer aktiven Klasse auf der Bootstrap-Menüseite in der Rails-Ansicht.

    <li class="<%= 'active' if current_page?(root_path) %>"><%= link_to 'Home', controller: "welcome" %></li>
    <li class="<%= 'active' if current_page?(about_path) %>"><%= link_to 'About us', about_path %></li>
   <li class="<%= 'active' if current_page?(contact_path) %>"><%= link_to 'Contact us', contact_path %></li>
Kleiner Phild
quelle
3

Ich benutze ein tolles Juwel namens Tabs on Rails .

Eis
quelle
1
Danke für den Vorschlag. Da mein Navi so einfach ist und es nur eines mit kleinen Gegenständen gibt, wäre der Edelstein wahrscheinlich überlastet.
PeterWong
3

Ich habe eine prägnantere Version von nav_link, die genau wie link_to funktioniert, aber angepasst ist, um ein umhüllendes li-Tag auszugeben.

Fügen Sie Folgendes in Ihre application_helper.rb ein

def nav_link(*args, &block)
    if block_given?
      options      = args.first || {}
      html_options = args.second
      nav_link(capture(&block), options, html_options)
    else
      name         = args[0]
      options      = args[1] || {}
      html_options = args[2]

      html_options = convert_options_to_data_attributes(options, html_options)
      url = url_for(options)

      class_name = current_page?(url) ? 'active' : nil

      href = html_options['href']
      tag_options = tag_options(html_options)

      href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
      "<li class=\"#{class_name}\"><a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a></li>".html_safe
    end
  end

Wenn Sie sich den obigen Code ansehen und ihn mit dem link_to-Code in url_helper.rb vergleichen, besteht der einzige Unterschied darin, dass überprüft wird, ob die URL die aktuelle Seite ist, und die Klasse "active" zu einem umhüllenden li-Tag hinzugefügt wird. Dies liegt daran, dass ich den nav_link-Helfer mit der nav-Komponente von Twitter Bootstrap verwende, die bevorzugt, dass Links in li-Tags eingeschlossen werden und die "aktive" Klasse auf das äußere li angewendet wird.

Das Schöne am obigen Code ist, dass Sie einen Block in die Funktion übergeben können, genau wie Sie es mit link_to tun können.

Eine Bootstrap-Navigationsliste mit Symbolen würde beispielsweise folgendermaßen aussehen:

Schlank:

ul.nav.nav-list
  =nav_link root_path do
    i.icon-home
    |  Home
  =nav_link "#" do
    i.icon-user
    |  Users

Ausgabe:

<ul class="nav nav-list">
  <li class="active">
    <a href="/">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>

Darüber hinaus können Sie genau wie der link_to-Helfer HTML-Optionen an nav_link übergeben, die auf das a-Tag angewendet werden.

Ein Beispiel für die Übergabe eines Titels für den Anker:

Schlank:

ul.nav.nav-list
  =nav_link root_path, title:"Home" do
    i.icon-home
    |  Home
  =nav_link "#", title:"Users" do
    i.icon-user
    |  Users

Ausgabe:

<ul class="nav nav-list">
  <li class="active">
    <a href="/" title="Home">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#" title="Users">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>
Joe Chen
quelle
Genial. Für mich war dies die praktikabelste Option, gerade weil sie Blöcke zulässt. Danke vielmals!
Kasperi
3

Für mich persönlich habe ich hier eine Kombination von Antworten verwendet

<li class="<%= 'active' if current_page?(inventory_index_path) %>"><a href="#">Menu</a></li>

Ich verwende materialise css und meine Art, die Hauptkategorien zusammenklappbar zu machen, ist die Verwendung des folgenden Codes

$('.active').closest(".collapsible.collapsible-accordion")
            .find(".collapsible-header")
            .click();

hoffe es hilft jemandem

Petros Kyriakou
quelle
habe das vergessen. Vielen Dank für die Veröffentlichung als Erinnerung.
Newdark-It
2

Die current_page?Methode ist für mich nicht flexibel genug (sagen wir, Sie legen einen Controller fest, aber keine Aktion, dann wird nur bei der Indexaktion des Controllers true zurückgegeben), daher habe ich dies basierend auf den anderen Antworten gemacht:

  def nav_link_to(link_text, link_path, checks=nil)
    active = false
    if not checks.nil?
      active = true
      checks.each do |check,v|
        if not v.include? params[check]
          active = false
          break
        end
      end
    end

    return content_tag :li, :class => (active ? 'active' : '') do
      link_to link_text, link_path
    end
  end

Beispiel:

nav_link_to "Pages", pages_url, :controller => 'pages'
Unrelativität
quelle
Vielen Dank für Ihre Antwort. Ich denke, deine ähnelt der akzeptierten Antwort tatsächlich :)
PeterWong
Ich bin auf diese Antwort über Google
gestoßen,
2

Ja! Lesen Sie diesen Artikel: Eine bessere Möglichkeit, Links in Rails eine 'ausgewählte' Klasse hinzuzufügen

Legen Sie nav_link_helper.rb in app / helpers ab und es kann so einfach sein wie:

<%= nav_link 'My_Page', 'http://example.com/page' %>

Der nav_link-Helper funktioniert genau wie der standardmäßige Rails link_to-Helfer, fügt jedoch Ihrem Link (oder seinem Wrapper) eine 'ausgewählte' Klasse hinzu, wenn bestimmte Kriterien erfüllt sind. Wenn die Ziel-URL des Links mit der URL der aktuellen Seite übereinstimmt, wird dem Link standardmäßig die Standardklasse "Ausgewählt" hinzugefügt.

Hier gibt es einen Kern: https://gist.github.com/3279194

UPDATE: Dies ist jetzt ein Juwel: http://rubygems.org/gems/nav_link_to

Dan Tello
quelle
Das ist nett. Ich nahm in Gebrauch und fügte eine Modifikation hinzu, um zu unterstützen, den nicht ausgewählten Elementen einen Klassennamen zu geben, auch als Kommentar im Kern.
Teemu Leisti
2

Ich verwende einen einfachen Helfer wie diesen für Links der obersten Ebene, damit die /stories/my-storySeite den /storiesLink hervorhebt

def nav_link text, url

  active = (url == request.fullpath || (url != '/' && request.fullpath[0..(url.size-1)] == url))

  "<li#{ active ? " class='selected'" : '' }><a href='#{url}'>#{text}</a></li>".html_safe

end
komplistisch
quelle
2

Lassen Sie mich meine Lösung zeigen:

_header.html.erb :

  <ul class="nav">
    <%= nav_tabs(@tabs) %> 
  </ul>

application_helper.rb :

 def nav_tabs(tabs=[])
    html = []
    tabs.each do |tab| 
      html << (content_tag :li, :class => ("current-page" if request.fullpath.split(/[\??]/)[0] == tab[:path]) do
        link_to tab[:path] do
          content_tag(:i, '', :class => tab[:icon]) +
          tag(:br) +
          "#{tab[:name]}"
        end
      end)        
    end

    html.join.html_safe
  end

application_controller.rb :

before_filter :set_navigation_tabs

private
def set_navigation_tabs
  @tabs = 
    if current_user && manager?
      [
        { :name => "Home", :icon => "icon-home", :path => home_index_path },
        { :name => "Portfolio", :icon => "icon-camera", :path => portfolio_home_index_path },
        { :name => "Contact", :icon => "icon-envelope-alt", :path => contact_home_index_path }
      ]
    elsif current_user && client?
      ...
    end
Mike Andrianov
quelle
1

Nach der Antwort von Skilldrick werde ich Folgendes ändern:

def nav_link(*args, &block)
  is_active = current_page?(args[0]) || current_page?(args[1])
  class_name = is_active ? 'active' : nil

  content_tag(:li, class: class_name) do
    link_to *args, &block
  end
end

um es viel nützlicher zu machen.

Tom Chen
quelle
1

Diese Version basiert auf der von @ Skilldrick, ermöglicht jedoch das Hinzufügen von HTML-Inhalten.

So können Sie tun:

nav_link "A Page", a_page_path

aber auch:

nav_link a_page_path do
  <strong>A Page</strong>
end

oder andere HTML-Inhalte (Sie können beispielsweise ein Symbol hinzufügen).

Hier ist der Helfer:

  def nav_link(name = nil, options = nil, html_options = nil, &block)
    html_options, options, name = options, name, block if block_given?
    options ||= {}

    html_options = convert_options_to_data_attributes(options, html_options)

    url = url_for(options)
    html_options['href'] ||= url

    class_name = current_page?(url) ? 'current' : ''
    content_tag(:li, :class => class_name) do  
      content_tag(:a, name || url, html_options, &block)
    end
  end
Benjamin J. Benoudis
quelle
1

Ich denke, ich habe eine einfache Lösung gefunden, die für viele Anwendungsfälle hilfreich sein könnte. Das lässt mich:

  • Unterstützt nicht nur einfachen Text, sondern auch HTML link_to(z. B. Hinzufügen eines Symbols innerhalb des Links)
  • Fügen Sie nur wenige Codezeilen hinzu application_helper.rb
  • Hängen Sie activean den gesamten Klassennamen des Link-Elements an, anstatt dass es die einzige Klasse ist.

Fügen Sie dies also hinzu zu application_helper.rb:

def active_class?(class_name = nil, path)
  class_name ||= ""
  class_name += " active" if current_page?(path)
  class_name.strip!
  return class_name
end

Und auf Ihrer Vorlage können Sie so etwas haben:

<div class="col-xs-3">
  <%= link_to root_path, :class => active_class?("btn btn-outline-primary", root_path) do %>
    <i class="fa fa-list-alt fa-fw"></i>
  <% end %>
</div>

Als Bonus können Sie a angeben oder nicht class_nameund es wie folgt verwenden:<div class="<%= current_page?(root_path) %>">

Dank vorheriger Antworten 1 , 2 und Ressourcen .

Juan Diego Gonzales
quelle
0

Alle diese Funktionen funktionieren mit einfachen Navigationsleisten, aber was ist mit dem Dropdown-Untermenü? Wenn ein Untermenü ausgewählt ist, sollte der oberste Menüpunkt 'aktuell' gemacht werden. In diesem Fall ist tabs_on_rails die Lösung


quelle
0

So habe ich es in meinem aktuellen Projekt gelöst.

def class_if_current_page(current_page = {}, *my_class)
    if current_page?(current_page)
      my_class.each do |klass|
        "#{klass} "
      end
    end
  end

Dann..

li = link_to company_path 
    class: %w{ class_if_current_page( { status: "pending" }, "active" ), "company" } do  
      Current Company
GN.
quelle
0

Mein einfacher Weg -

application.html.erb,

<div class="navbar">
    <div class="<%= @menu1_current %> first-item"><a href="/menu1"> MENU1 </a></div>
    <div class="<%= @menu2_current %>"><a href="/menu2"> MENU2 </a></div>
    <div class="<%= @menu3_current %>"><a href="/menu3"> MENU3 </a></div>
    <div class="<%= @menu4_current %> last-item"><a href="/menu4"> MENU4 </a></div>
</div>

main_controller.erb,

class MainController < ApplicationController
    def menu1
        @menu1_current = "current"
    end

    def menu2
        @menu2_current = "current"
    end

    def menu3
        @menu3_current = "current"
    end

    def menu4
        @menu4_current = "current"
    end
end

Vielen Dank.

Lwin Htoo Ko
quelle
0

Wenn Sie auch HTML-Optionen Hash in der Ansicht unterstützen möchten. Wenn Sie es beispielsweise mit einer anderen CSS-Klasse oder -ID aufrufen möchten, können Sie die Hilfsfunktion wie folgt definieren.

def nav_link_to(text, url, options = {})
  options[:class] ||= ""
  options[:class] += " active"
  options[:class].strip!
  link_to text, url, options
end

Rufen Sie diesen Helfer in der Ansicht genauso auf, wie Sie link_to helper aufrufen würden

<%= nav_link_to "About", about_path, class: "my-css-class" %>
Ken Hibino
quelle
0

Erstellen Sie eine Methode ApplicationHelperwie folgt.

def active controllers, action_names = nil
  class_name = controllers.split(",").any? { |c| controller.controller_name == c.strip } ? "active" : ""
  if class_name.present? && action_names.present?
    return action_names.split(",").any? { |an| controller.action_name == an.strip } ? "active" : ""
  end
  class_name
end

Verwenden Sie es jetzt in der folgenden Ansicht.

1. Für alle Aktionen eines bestimmten Controllers

<li class="<%= active('controller_name')%>">
....
</li>

2. Für alle Aktionen vieler Controller (mit Komma getrennt)

<li class="<%= active('controller_name1,controller_name2')%>">
....
</li>

3. Für bestimmte Aktionen eines bestimmten Controllers

<li class="<%= active('controller_name', 'action_name')%>">
....
</li>

4. Für die spezifische Aktion vieler Steuerungen (durch Komma getrennt)

<li class="<%= active('controller_name1,controller_name2', 'action_name')%>">
....
</li>

5. Für einige bestimmte Aktionen eines bestimmten Controllers

<li class="<%= active('controller_name', 'index, show')%>">
....
</li>

6. Für einige spezifische Aktionen vieler Controller (durch Komma getrennt)

<li class="<%= active('controller_name1,controller_name2', 'index, show')%>">
....
</li>

Ich hoffe es hilft

Lalit Kumar Maurya
quelle