18

I'm using Bootstrap v4.0.0

I have included the necessary JavaScript files (jQuery, popper and Bootstrap) and the necessary CSS files as well.

This is the HTML:

<body data-spy="scroll" data-target="#my-navbar-collapse" data-offset="100">
    <!-- ... -->
    <div class="collapse navbar-collapse" id="my-navbar-collapse">
        <ul class="nav navbar-nav" role="tablist">
            <li class="nav-item">
                <a class="nav-link" href="#one">One</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#two">Two</a>
            </li>
        </ul>
    </div>
    <!-- ... -->
    <section id="one">
        Content.
    </section>
    <!-- ... -->
    <section id="two">
        More content.
    </section>
    <!-- ... -->
    <script>
        $(function() {
            // As per the official docs: 
            // https://getbootstrap.com/docs/4.0/components/scrollspy/#events
            $('[data-spy="scroll"]').on('activate.bs.scrollspy', function() {
                console.log("This event is not firing...");
            });
        });
    </script>
</body>

The menu items get highlighted properly when scrolling, but the JavaScript event activate.bs.scrollspy is not firing.

I also tried to hook the event to the navbar itself, but it does not fire either:

$('#my-navbar-collapse').on('activate.bs.scrollspy', function () {
    console.log("Not firing either...");
})

I used to use this code with Bootstrap 3 and worked just fine.

Any thoughts?

Thank you.

Alessio Cantarella
  • 5,077
  • 3
  • 27
  • 34
zed
  • 2,298
  • 4
  • 27
  • 44

2 Answers2

39

For some reason explained here, when you use body for the spy element the event gets activated on the window.

        $(window).on('activate.bs.scrollspy', function () {
            console.log("This event is not firing...");
        });

Demo: https://www.codeply.com/go/aN4tfy0zU0

EDIT

The target element can be obtained in the 2nd event param:

      $(window).on('activate.bs.scrollspy', function (e,obj) {
          console.log(obj.relatedTarget);
      });
Carol Skelly
  • 351,302
  • 90
  • 710
  • 624
  • That solved it!. Thank you. By any chance, do you know how to get the current anchor? I used to do it like this: `$(window).on('activate.bs.scrollspy', function (e) { var anchor = $(e.target).find('a'); });` -- Or I could ask a separate question. – zed Feb 08 '18 at 20:36
  • 4
    In Bootstrap 5 there does not appear to be a 2nd parameter so you get the target element from e.relatedTarget – Joe Hakooz Jun 09 '21 at 20:45
  • Joe and Zim - dream team! Those two answers combined let me find out what element was targetted in bootstrap 5. – CeeGee Jul 21 '22 at 10:52
1

@kim gave the right answer, but I also needed to hook to a scroll-end event, which does not seem to exist - so created something simple using a timeout:

// reset scroll watcher ##
clearTimeout( jQuery.data(this, 'scrollTimer'));

jQuery(window).on('activate.bs.scrollspy', function ( e,obj ) {
        
    // console.log(obj.relatedTarget);
        
    jQuery.data( this, 'scrollTimer', setTimeout(function() {
            
        // console.log("Didn't scroll in 1/4 sec..");

        // no scroll items are marked as active ##
        if ( ! jQuery(".scrollspy-item.active")[0]){ 

            // console.log("Can't fund any active scrollspy items..");

            // add class to parent again ##
            jQuery(".list-group-item.current").addClass( 'active' );

        }

    }, 250 ) );

});

In this case, I'm checking if any "scrollspy-items" are marked as active, or not and then adding the active class to a parent item, as we use the scrollspy in place in a sidebar menu.

Q Studio
  • 1,811
  • 3
  • 16
  • 18