Dynamically add active class to bootstrap li in Rails
Asked Answered
R

7

30

in the bootstrap navigation bar. You can get the effect of a button being clicked by adding the class active . Naturally, I want to use this on my pages. For example if I'm on the about us page I want the about us button clicked.

What is the best way to go about this? I was going to go to each page and at the bottom have a jQuery function add the class active to it. Is there a better way?

Regenaregency answered 5/7, 2013 at 5:42 Comment(0)
K
58

Read about current_page? here

You can add a method for handle logic with current_page?, example a method :

module ApplicationHelper

 def active_class(link_path)
  current_page?(link_path) ? "active" : ""
 end

end

example bootstrap navbar template

<div class="navbar">
  <div class="navbar-inner">
    <a class="brand" href="#">Title</a>
    <ul class="nav">
      <li class="active"><a href="#">Home</a></li>
      <li><a href="#">Link</a></li>
      <li><a href="#">Link</a></li>
    </ul>
  </div>
</div>

So, on view looks like

HTML

<li class="<%= active_class(some_path) %>">
<%= link_to "text of link", some_path %>
</li>

HAML

%li{:class => active_class(some_path)}
  = link_to "text of link", some_path

Or you can use request.fullpath to get current full of path if a current path have a parameter

example

<ul>
 <% Contry.all.each do |c| %>
  <li class="snavitem <%= active_class(contry_path(c)) %>">
    <%= link_to "show #{c.name}", contry_path(c) %>
  </li>
 <% end %>
</ul>

and on your application_helper.rb

def active_class(link_path)
  request.fullpath == link_path ? "active" : "" 
end

read about request.fullpath here

Karlis answered 5/7, 2013 at 6:5 Comment(6)
You not says on your questions if you are using haml. updated answerKarlis
Sorry but you got it to work thank you. But why wouldn't %li{:class => is_active?(some_path)} work?Regenaregency
Glad to help!, have you added is_active? method on helper?Karlis
no i did what you said and got it to work i'm just curious as to why %li{:class => is_active?(some_path)} would not workRegenaregency
because you don't have is_active? method on helper, is_active?(some_path) will call is_active? method.Karlis
Being overly pedantic here, but methods ending in question mark should probably return boolean values, not a CSS class string.Lemcke
E
14

in my opinion, a cleaner way to achieve that is to write a link_to_in_li method in application_helper.rb:

def link_to_in_li(body, url, html_options = {})
  active = "active" if current_page?(url)
  content_tag :li, class: active do
    link_to body, url, html_options
  end
end

then use it this way

<%= link_to_in_li "Home", root_path, id: "home_link" %>

I find the code inside li a little difficult to read.

Elena answered 9/4, 2014 at 23:50 Comment(4)
Very clever in Rails way.Fiscus
Easiest answer I found. Also, if you need to have multiple classes on the <li> element you can simply add the additional classes like so: content_tag :li, class: "#{active} other-class" doFamilial
This works great, I've been trying many other solutions and this is the best for me.Pelligrini
I think this is the best solution I've read up to now. It is DRY, and it only requires to add _in_li to the url helpers you might already have, because it takes the same arguments. Thanks.Upbraiding
N
6

For anyone having trouble making sense of this, here is an example with my paths and filenames laid out explicitly. As a pretty new person to rails, I was having trouble figuring it out. Thanks to the other people who answered above, as it helped me figure it out!

I placed the Bootstrap navbar in my application.html.erb file:

<div class="navbar-header">

  <a class="navbar-brand" href="/">Mapper</a>
  <ul class="nav navbar-nav">

    <li class="<%= is_active?('/') %>"><%= link_to "Home", '/' %></li>
    <li class="<%= is_active?('/main/map') %>"><%= link_to "Map", '/main/map' %></li>
    <li class="<%= is_active?('/main/about') %>"><%= link_to "About", '/main/about' %></li>

  </ul>
</div>

This goes in the application_helper.rb file:

module ApplicationHelper

def is_active?(link_path)
 current_page?(link_path) ? "active" : ""
end

end

That's it! Now your application will dynamically add the 'active' class to whatever page is currently being viewed (i.e. it's corresponding list item in the navbar). This is much simpler (and more DRY) than adding the navbar manually to each page (view) and then updating the 'active' class.

Necromancy answered 19/5, 2014 at 17:49 Comment(2)
Good solution. Perfect for me.Liminal
thank very much this helped me way more than the other answers since I too am very new to rails.Windermere
E
3

I'll post my answer that I created based on these others because in case of CRUD views the active class wasn't been placed.

module ApplicationHelper
 def active_class(name)
   controller_name.eql?(name) || current_page?(name) ? 'active' : ''
 end
end

My views use something like this:

  <ul class="nav navbar-nav">
    <li class="nav-item <%= active_class('/') %>">
      <a class="nav-link" href="/">Home</a>
    </li>
    <li class="nav-item <%= active_class('leads') %>">
      <a class="nav-link" href="/leads">Leads</a>
    </li>
  </ul>
  <ul class="nav navbar-nav pull-right <%= active_class(edit_user_registration_path) %>">
    <li class="nav-item ">
      <a class="nav-link" href="/users/edit">Perfil</a>
    </li>
    <li class="nav-item">
      <%= link_to('Sair', destroy_user_session_path, method: :delete) %>
    </li>
  </ul>
Equivalency answered 3/5, 2016 at 11:56 Comment(0)
B
2

Please try this in each page, check the cotroller or action and add the css

For example:

<li class= <%= (controller.controller_name.eql?('pages') && controller.action_name.eql?('index') )? 'active':''%> ><%= link_to 'my page', pages_path%></li>
Beaconsfield answered 5/7, 2013 at 6:26 Comment(0)
P
1

You may define a helper method in application_helper.rb

def create_link(text, path)
  class_name = current_page?(path) ? 'active' : ''

  content_tag(:li, class: class_name) do
    link_to text, path
  end
end

Now you can use like:

create_link 'xyz', any_path which would render as <li class="active"><a href="/any">xyz</a></li>

Perfect for bootstrap navigation!

Padriac answered 20/10, 2015 at 8:41 Comment(0)
F
1

Why limit yourself to only li elements? And why not support multiple class names along with active? This solution lets me:

  • Support not only plain text but HTML inside link_to (e.g. add an icon inside the link)
  • Add just few lines of code to application_helper.rb
  • Append active to the whole class name of the link element instead of it being the sole class.

So, add this to 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

And on your template you can have something like this:

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

You can also specify or not a class_name and use it like this:

<li class="<%= active_class?(root_path) %>">Home</li>

Thanks to previous answers 1, 2 and resources.

Felting answered 8/1, 2017 at 14:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.