Set Current Link Class with jQuery
The other day I was was trying to DRY up the code in a rails application I was working on by reusing a view that’s not a partial. I took care of the models to display in the controller but needed to show which link was active by adding the CSS class current
.
My first thought was to pass something, say a hash called @link_class
with possible links, through the controller.
def show
@user = User.find(params[:id])
@stuff = @user.stuff
@link_class = {}
@link_class[:my_stuff] = 'current'
end
def show_liked_stuff
@user = User.find(params[:id])
@stuff = @user.liked_stuff
@link_class = {}
@link_class[:likes] = 'current'
render :show
end
And in my view…
<li><%= link_to 'Likes', user_liked_stuff_path(@user), class: @link_class[:likes] %></li>
<li><%= link_to 'My Stuff', user_path(@user), class: @link_class[:my_stuff] %></li>
But that left a terrible taste in my mouth. I knew it wasn’t the beer I was drinking, so I set out to craft a more elegant solution. 🍺
JavaScript has some nifty ways to grab the current URL such as window.location.href
and window.location.pathname
. The former will grab the entire URL while the latter will just grab the path after the protocol and domain. Pathname is what I was looking for since in my rails app I have mostly relative links to navigate around. So now I was thinking that I could somehow match the current pathname with the link and add the class I needed.
Good thing for me, jQuery can select elements by attribute and value. I can add the class for the parent element user-nav
to my selector to make sure I don’t grab a link from my header or elsewhere.
$('.user-nav [href="' + window.location.pathname + '"]')
I slapped that into the console in Firefox dev tools…it works! Now I just have to add the class I need. I can use className from plain old JavaScript to do that!
$('.user-nav [href="' + window.location.pathname + '"]').className = "current";
Eureka! But what if I want to reuse this with a different nav? How about a function?
function setNavLinkClassToCurrent(navClass) {
$(navClass + ' [href="' + window.location.pathname + '"]').className = "current";
}
Now we’re talking! I can reuse this puppy by just calling setNavLinkClassToCurrent('.user-nav')
, setNavLinkClassToCurrent('.main-nav')
, or setNavLinkClassToCurrent('.beer-nav')
. I could even go a step further if we wanted to have our pick of CSS classes to apply.
function setCurrentNavLinkClass(navClass, linkClass) {
$(navClass + ' [href="' + window.location.pathname + '"]').className = linkClass;
}
Cool! I can do setCurrentNavLinkClass('.user-nav', 'current')
or setCurrentNavLinkClass('.main-nav', 'bananas')
or whatever else floats my boat.