jquerywordpressnavigationanchoranchor-scroll

Wordpress/jQuery: Highlight matching anchors when div is in viewport on scroll


I am currently trying to implement a menu for a Wordpress website with following criteria:

  1. When the user scrolls down the page and reaches an anchored div (linked in the menu), the link in the menu should get the class "active".
  2. When the user clicks on an anchor, the page should scroll to the anchored div, and the link should receive the "active" class.

Here is the HTML from that page:

<nav class="sub-navigation">
<ul class="secondary-link">
<li><a href="#team"><span>Team</span></a></li>
<li><a href="#guidelines"><span>Guidelines</span></a></li>
<li><a href="#clients"><span>Clients</span></a></li>
</ul>
</nav>

The following code almost works - however, it throws the following error:

Uncaught Error: Syntax error, unrecognized expression: http://domain.com/not-the-current-page

jQuery(document).ready(function() {
 
  jQuery(document).on("scroll", onScroll);
  jQuery('.secondary-link a').click(function(event) {
    event.preventDefault();
    jQuery(document).off("scroll");
    var link = this; 
    jQuery.smoothScroll({
      offset: -100,
      speed: 1000,
      scrollTarget: link.hash
    });
  });
  jQuery('.secondary-link a').click(function(){
    jQuery('.secondary-link a').removeClass('active');
    jQuery(this).addClass('active');
    jQuery(document).on("scroll", onScroll);
  });

  function onScroll(event){
    var scrollPos = jQuery(document).scrollTop();
    jQuery('.secondary-link a').each(function () {
        var currLink = jQuery(this);
        var refElement = jQuery(currLink.attr('href'));
        if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
            jQuery('.secondary-link a').removeClass("active");
            currLink.addClass("active");
        }
        else{
            currLink.removeClass("active");
        }
    });
  }
});

Logic is as follows:

  1. Listen for scroll and add "active" class accordingly.
  2. When the link is clicked, stop (1.), scroll to anchor, add class "active", then resume (1.)

This is my first work with jQuery. I hope one of you can point me in the right direction on how to get this working correctly. Your help is greatly appreciated!


Solution

  • Finally figured out what was going wrong:

    1. The menu contained a link that was not an anchor, hence the error Uncaught Error: Syntax error, unrecognized expression: http://domain.com/not-the-current-page

    After resolving this, another error appeared:

    Uncaught TypeError: Cannot read property 'top' of undefined
    

    I got rid of this one by following the logic here

    Basically I had to check if the jQuery object contains any element before I tried to get its offset.

    The working jQuery code for link highlighting and smooth scrolling now looks like this:

     jQuery(document).ready(function() {
      jQuery(document).on("scroll", onScroll);
      jQuery('.secondary-link a').click(function(event) {
        event.preventDefault();
        jQuery(document).off("scroll");
        var link = this;
        jQuery.smoothScroll({
          offset: -100,
          speed: 1000,
          scrollTarget: link.hash
        });
      });
    
      jQuery('.secondary-link a').click(function(){
        jQuery(document).off("scroll");
        jQuery('.secondary-link a').removeClass('active');
        jQuery(this).addClass('active');
        jQuery(document).on("scroll", onScroll);
      });
    
      function onScroll(event){
        var scrollPos = jQuery(document).scrollTop();
        jQuery('.secondary-link a').each(function () {
            var currLink = jQuery(this);
            var refElement = jQuery(currLink.attr('href'));
            if (refElement.length) {
            if (refElement.position().top-100 <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
                jQuery('.secondary-link a').removeClass("active");
                currLink.addClass("active");
            }
            else{
                currLink.removeClass("active");
            }
            }
        });
      }
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

    In order to reproduce, you will need the smoothscroll library available here. This is working overall, not sure about performance, however. Cheers!