Search code examples
jqueryattributesjquery-waypoints

jQuery - Get the attribute of multiple elements and match it to other elements' ids?


How can I get jQuery to compare an id to an attribute and if matching add an .activeclass to the element with the matching attribute?

I'm trying to refactor a long and repetitive jQuery code. I have set waypoints to trigger on scroll, once you reach a certain section it adds an active class to the menu link that refers to the section. This is the best I could manage, but it is not working.

$('section').waypoint(function(direction) {
  if (direction === 'down') {
    $('nav a').removeClass('active-nav');
    var linkName = $('nav a').map( function() {
    return $(this).attr('href');
    }).get();
    if(linkName == $('section[id]')){
         $(this).addClass('active-nav');
        }
  }
}, {
  offset: '25%'
});

The thinking behind this is that my section id is the same as the hrefvalue of the menu link (it's an anchor bookmark), so my logic is: Compare thesection idto the nav a href value, and if they match addClass .active to this menu link. How can I achieve this logic?

a- How do I get the hrefof all the links in nav?

b- How do I then compare it to the section id andaddClassto the nav link that matches?

my html looks something like this:

<nav>
 <a id="b1" href="#landing">Home</a>
 <a id="b2" href="#portfolio">Portfolio</a>
 <a id="b3" href="#experience">Experience</a>
 <a id="b4" href="#about">About</a>
</nav>

<section id="landing">some content</section>
<section id="portfolio">some content</section>
<section id="experience">some content</section>
<section id="about">some content</section>

And my current jQuery looks like this

$('#landing').waypoint(function(direction) {
  if (direction === 'down') {
    $('nav a').removeClass('active-nav');
    $('#b1').addClass('active-nav');
  }
}, {
  offset: '25%'
});

$('#landing').waypoint(function(direction) {
  if (direction === 'up') {
    $('nav a').removeClass('active-nav');
    $('#b1').addClass('active-nav');
  }
}, {
  offset: '-25%'
});

Which works just fine but has to be repeated for every section individually.


Solution

  • Instead of using the id of each section and attaching handlers, you can use the section selector like this:

    // this event is called for all sections.
    $('section').waypoint(function(direction) {
      if (direction === 'down') {
        $('nav a').removeClass('active-nav');
    
        // form the selector dynamically.
        // "this" keyword refers waypoint object and the element is located at "this.element"
        // using "this.element.id", get the nav anchor you want to target
        // example: "nav a[href='#landing']"
    
        var selector = "nav a[href='#" + this.element.id + "']"; 
        $(selector).addClass('active-nav');
      }
    }, {
      offset: '25%'
    });
    

    $('section').waypoint(function(direction) {
      if (direction === 'up') {
        $('nav a').removeClass('active-nav');
        var selector = "nav a[href='#" + this.element.id + "']"; 
        $(selector).addClass('active-nav');
      }
    }, {
      offset: '-25%'
    });
    

    There are different ways to get the target element you want. In your case, since the section and a elements are in the same order, you can use .index() and eq(n) (Important: You need to wrap your sections with a div for "index()" to work.)

    // this event is called for all sections.
    $('section').waypoint(function(direction) {
      if (direction === 'down') {
        $('nav a').removeClass('active-nav');
        $("nav a").eq($(this.element).index()).addClass('active-nav');
      }
    }, {
      offset: '25%'
    });
    

    I have created a fiddle for the second way of doing. Test it and let me know.