WickyNilliams / headroom.js

Give your pages some headroom. Hide your header until you need it
https://wicky.nillia.ms/headroom.js/
MIT License
10.86k stars 824 forks source link

How to programmatically enable/disable pinning on a page? #265

Closed Jakobud closed 7 years ago

Jakobud commented 7 years ago

I have a website where the header uses Headroom to pin itself when the user scrolls up on the page. Headroom adds the headroom--pinned as expected. But on a particular page, where I have some automated scrolling events happening, it would be ideal to be able to programmatically disable and re-enable the pinning of Headroom while things are happening on the page.

Is it possible to programmatically control the pinning/unpinning that Headroom does on a page (and not just one time when the page load and Headroom is instantiated).

My only solution so far that I could think of is to add some !important class to the header that would override the .headroom--pinned class, but that seems like a messy way to do things.

Jakobud commented 7 years ago

Alternatively is it possible to set the .onPin function on the fly (as opposed to only when you init headroom)?

WickyNilliams commented 7 years ago

You could destroy and create a new instance whenever your conditions are met. This should be fine in most cases.

For onPin, instead of setting on the fly (presumably when some condition is met), always set onPin and put the conditional logic in the callback.

Hope that helps

Jakobud commented 7 years ago

Thank you for the reply. Some of these things aren't possible in my CMS I am dealing with because I cannot access or control the code that instantiates the Headroom functionality in the header. So I can't get in there and define or change an onPin callback.

Have you ever considered just emitting generic JavaScript events that any script can listen/subscribe to?

// In headroom.js
var pinEvent = new Event('pin');
headerElement.dispatchEvent(pinEvent);

// Some random script
headerElement.addEventListener('pin', function(e){
  console.log('The header was pinned!')
}, false);

It would be pretty simple to do and would give more flexibility for any scripts wanting to trigger something based off of Headroom events without having to modify the original instantiating code or resort to destroying/remaking the component.

WickyNilliams commented 7 years ago

Events have been discussed extensively in the past. Please search the issue tracker for my reasoning behind the current approach. See #31.

Closing this in the interest of cleaning up the issue tracker. But I am happy to continue discussion if you wish

Jakobud commented 7 years ago

Thanks. So that issue is from 2013. Do you still have the same opinion on callbacks vs events? Quite a bit has changed in the JS world since then, especially when you consider frameworks like Angular and React, especially considering how much they rely on events.

As you can see in my problem above, the callback functionality just doesn't work in all cases because not everyone in all cases can change the callback definition during instantiation. In an ideal world once can always make those kind of changes, but if you are in some sort of CMS environment or dealing with a website theme on an ecommerce engine and you can't change that backend code, then you are very limited in these areas.

But a triggered event can be subscribed to by anyone at any time. There are no limitations. All headroom needs to do is emit/dispatch that event. Doesn't need to do anything else. Very little overhead here.

AlexanderFlatscher commented 6 years ago

I used something like this to programatically enable/disable headroom:

var disableHeadroom = () => {
    let headroom = $element.data('headroom');

    if(headroom){
        headroom.scroller.removeEventListener('scroll', headroom.debouncer, false);
    }
};

var enableHeadroom = () => {
    let headroom = $element.data('headroom');

    if(headroom){
        headroom.scroller.addEventListener('scroll', headroom.debouncer, false);
    }
};