Il modo migliore per aggiungere la classe "corrente" a nav in Rails 3


111

Ho alcune pagine statiche in un menu di navigazione. Voglio aggiungere una classe come "corrente" all'elemento attualmente visualizzato.

Il modo in cui lo faccio è aggiungere tonnellate di metodi di supporto (ciascuno per un elemento) per controllare il controller e l'azione.

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

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

C'è un modo migliore per farlo !? Il mio modo attuale è così stupido ...

Risposte:


56

Non è proprio una risposta qui, perché sto usando più o meno come te. Ho appena definito metodi di supporto per testare più controller o azioni:

In application_helper.rb

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

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

Quindi puoi utilizzare if controller?("homepage") && action?("index", "show")nelle tue visualizzazioni o altri metodi di supporto ...


Il tuo modo si adatta meglio quando ci sono alcune pagine gestite da controller / azioni diversi ma nella stessa voce di menu, giusto? Hai riscontrato più vantaggi ~?
— PeterWong

Nessun vantaggio in più se non la concisione della sintassi. Sono curioso di vedere se qualcun altro ha una soluzione migliore.
— Yannis

Ho fatto questo metodo con grande successo. Aggiunto questo codice alla vista: <% = link_to "Users", users_path, class: (controller? ("Users")? 'Selected': nil)%> Davvero carino che funziona sia per / users che / users / new .
— Andreas

1
un miglioramento potrebbe essere controller_namee action_nameinvece dei parametri probabilmente
— Francesco Belladonna

Molto bene. Non pensavo di mantenerlo semplice, ma scala molto bene. +1
— newdark-it

290

Ho creato un aiutante chiamato 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

usato come:

nav_link 'Home', root_path

che produrrà HTML come

<li class="current"><a href="/">Home</a></li>

3
Funziona benissimo con Twitter ootstrap se stai utilizzando la barra di navigazione bootstrap di Twitter twitter.github.com/bootstrap/examples/hero.html
— Lee McAlilly,

41
Passare a class_name = current_page? (Link_path)? 'current': nil se non vuoi che il tag class venga mostrato quando non è nella pagina corrente
— Matthew Hui

1
Come lo modificheresti per gli elenchi nidificati utilizzati nei menu a discesa?
— doremi

9
ASCIUTTO come un deserto
— Orlando

1
Ho aggiunto alcuni argomenti extra extra_classes = nil, id = nil quindi all'interno di content_tag content_tag (: li, class: [class_name, extra_classes], id: id) in modo che tu possa aggiungere anche le tue classi e i tuoi ID agli elementi :)
— Jon

72

Usa l' current_page?helper per determinare se assegnare o meno la "current"classe. Per esempio:

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

Nota è anche possibile passare un percorso (non solo un hash di opzioni), ad esempio: current_page?(root_path).


3
C'è un modo per far sì che questo ignori i parametri della query?
— Mohamad

@ Mohamad, puoi farlo: current_page? (Controller: 'users', action: 'index')
— nilid

26

Uso questa funzione nav_link (text, link) in application_helper.rb (Rails 3) per portare a termine il lavoro e mi fa rotolare i link della barra di navigazione bootstrap twitter 2.0 per me.

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

Esempio:

<%=nav_link("About Us", about_path) %>

Ciò potrebbe essere semplificato utilizzando il current_page?metodo, come in altre risposte.
— Teemu Leisti

10

Il modo in cui l'ho fatto è aggiungere una funzione di supporto in application_helper

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

Quindi nel navigatore,

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

Questo verifica il percorso del collegamento rispetto all'URI della pagina corrente e restituisce la classe corrente o una stringa vuota.

Non l'ho testato a fondo e sono molto nuovo in RoR (trasferito dopo un decennio con PHP) quindi se questo ha un grave difetto mi piacerebbe ascoltarlo.

Almeno in questo modo hai solo bisogno di 1 funzione di supporto e una semplice chiamata in ogni collegamento.


1
Solo un problema. Ho usato request.path invece di request_uri (request_uri non funzionava, forse problema con la versione di rails?). La tua risposta è pulita ed elegante secondo me.
— Tony

6

Per costruire la risposta di @Skilldrick ...

Se aggiungi questo codice a application.js, assicurerai che anche tutti i menu a discesa con figli attivi siano contrassegnati come attivi ...

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

Per ricapitolare il codice di supporto> Aggiungi un helper chiamato nav_link:

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

usato come:

nav_link_to 'Home', root_path

che produrrà HTML come

<li class="active"><a href="/">Home</a></li>

4

Penso che il modo migliore sia

application_helper.rb:

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

E nel menu:

<li class="<%= is_active('controller', 'action') %>">

va bene lasciare una classe vuota "" come quella?
— Harsha MV,

Sì. Può sembrare strano se visualizzi il codice sorgente vedendo un mucchio di attributi di classe vuoti, ma è HTML valido.
— kobaltz

Puoi usare <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>, non stamperà un attributo di classe per nil. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
— neonmate

4

So che è una risposta obsoleta , ma puoi facilmente ignorare tutti questi controlli della pagina corrente usando un link_to helper wrapper, chiamato active_link_to gem, funziona esattamente come vuoi, aggiungi una classe attiva al link della pagina corrente


4

Ecco l'esempio completo su come aggiungere una classe attiva nella pagina del menu bootstrap nella vista rails.

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

3

Uso una fantastica gemma chiamata Tabs on Rails .


1
Grazie per il suggerimento. Dal momento che la mia navigazione è così semplice e ce n'è solo una con piccoli oggetti, la gemma sarebbe probabilmente sovraccarica.
— PeterWong

3

Ho una versione più succinta di nav_link che funziona esattamente come link_to, ma è personalizzata per produrre un tag li avvolgente.

Metti quanto segue nel tuo application_helper.rb

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

Se guardi il codice sopra e lo confronti con il codice link_to in url_helper.rb, l'unica differenza è che controlla se l'URL è la pagina corrente e aggiunge la classe "attiva" a un tag li avvolgente. Questo perché sto usando l'helper nav_link con il componente nav di Twitter Bootstrap che preferisce che i collegamenti siano inseriti all'interno dei tag li e la classe "attiva" applicata al li esterno.

La cosa bella del codice sopra è che ti permette di passare un blocco nella funzione, proprio come puoi fare con link_to.

Ad esempio, un elenco di navigazione bootstrap con icone sarebbe simile a:

Sottile:

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

Produzione:

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

Inoltre, proprio come l'helper link_to, puoi passare le opzioni HTML a nav_link, che verrà applicato al tag a.

Un esempio di passaggio di un titolo per l'ancora:

Sottile:

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

Produzione:

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

Eccezionale. Per me questa è stata l'opzione più praticabile proprio perché consente i blocchi. Grazie mille!
— Kasperi

3

Per me personalmente ho usato una combinazione di risposte qui

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

Sto usando materialize css e il mio modo di rendere le categorie principali pieghevoli è usare il codice sottostante

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

spero che aiuti qualcuno


dimenticato di questo. Grazie per aver postato questo messaggio come promemoria.
— newdark-it

2

Il current_page?metodo non è abbastanza flessibile per me (supponiamo che imposti un controller ma non un'azione, quindi restituirà true solo sull'azione index del controller), quindi l'ho fatto in base alle altre risposte:

  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

Esempio:

nav_link_to "Pages", pages_url, :controller => 'pages'

La ringrazio per la risposta. Penso che la tua sia simile alla risposta accettata in realtà :)
— PeterWong

Ho trovato questa risposta tramite Google poiché avevo questo problema, quindi ho pensato di aiutare anche tutti gli altri che si imbattono in questo :)
— inrelatività

2

Sì! Dai un'occhiata a questo articolo: Un modo migliore per aggiungere una classe "selezionata" ai collegamenti in Rails

Trascina nav_link_helper.rb in app / helper e può essere facile come:

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

L'helper nav_link funziona proprio come l'helper link_to standard di Rails, ma aggiunge una classe 'selected' al tuo link (o al suo wrapper) se vengono soddisfatti determinati criteri. Per impostazione predefinita, se l'URL di destinazione del collegamento è lo stesso URL dell'URL della pagina corrente, al collegamento viene aggiunta una classe predefinita di "selezionato".

C'è un succo qui: https://gist.github.com/3279194

AGGIORNAMENTO: Questo ora è un gioiello: http://rubygems.org/gems/nav_link_to


Questo è carino. L'ho utilizzato e ho aggiunto una modifica per supportare l'assegnazione di un nome di classe agli elementi non selezionati, anche come commento nel succo.
— Teemu Leisti

2

Uso un semplice aiuto come questo per i collegamenti di primo livello, quindi la /stories/my-storypagina evidenzia il /storiescollegamento

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

2

Fammi mostrare la mia soluzione:

_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

1

Secondo la risposta di Skilldrick , lo cambierò come segue:

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

per renderlo molto più utile.


1

Questa versione è basata su quella di @ Skilldrick ma ti permette di aggiungere contenuti html.

Quindi, puoi fare:

nav_link "A Page", a_page_path

ma anche:

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

o qualsiasi altro contenuto html (puoi aggiungere un'icona per esempio).

Qui l'aiutante è:

  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

1

Penso di aver trovato una soluzione semplice che potrebbe essere utile per molti casi d'uso. Questo mi permette di:

  • Supporta non solo testo normale ma HTML all'interno link_to (ad es. Aggiungi un'icona all'interno del collegamento)
  • Aggiungi solo poche righe di codice a application_helper.rb
  • Aggiungi activeal nome della classe intera dell'elemento link invece di essere l'unica classe.

Quindi, aggiungi questo a 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

E sul tuo modello puoi avere qualcosa del genere:

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

Come bonus puoi specificare o meno a class_namee usarlo in questo modo:<div class="<%= current_page?(root_path) %>">

Grazie alle risposte precedenti 1 , 2 e alle risorse .


0

tutti questi funzionano con semplici barre di navigazione, ma per quanto riguarda il sottomenu a discesa? quando viene selezionato un sottomenu la voce di menu in alto dovrebbe essere resa 'corrente' in questo caso tabs_on_rails me essere la soluzione


0

È così che ho risolto nel mio progetto attuale.

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

Poi..

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

0

Il mio modo semplice -

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

Grazie.


0

Se vuoi anche supportare le opzioni html hash nella vista. Ad esempio, se vuoi chiamarlo con un'altra classe CSS o id, puoi definire la funzione di supporto in questo modo.

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

Quindi nella vista, chiama questo helper nello stesso modo in cui chiameresti link_to helper

<%= nav_link_to "About", about_path, class: "my-css-class" %>

0

Crea un metodo ApplicationHelpercome di seguito.

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

Ora usalo in vista come di seguito casi d'uso.

1. Per tutte le azioni di qualsiasi controller specifico

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

2. Per tutte le azioni di molti controller (con virgola separata)

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

3. Per azioni specifiche di qualsiasi controller specifico

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

4. Per azioni specifiche di molti controller (con virgola separata)

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

5. Per alcune azioni specifiche di qualsiasi controller specifico

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

6. Per alcune azioni specifiche di molti controller (con virgola separata)

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

Spero che sia d'aiuto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.