jqueryhtmlcssknockout.jsbindinghandlers

Trigger Knockout BindingHandler linked to KnockoutObservable on document.body.scrollTop


I am attempting to trigger a Knockout BindingHandler as a direct result of the document.body.scrolltop value being greater or equal to a particular value. I have attempted to create an observable based on a statement. Firstly, is this possible? Or should I be updating the boolean result as part of a computed?

scrollPosition: KnockoutObservable<boolean> = ko.observable(document.body.scrollTop >= 200)

I have also tried:

scrollPosition: KnockoutComputed<boolean> = ko.computed(() => {
    if (document.body.scrollTop >= 100) {
        return true;
    }
    else {
        return false;
    }
});

The rest of the relevant code is:

HTML

<a href="javascript:void(0);" id="topLink" data-bind="topScroll: scrollPosition"><i class="glyphicon glyphicon-stats"></i></a>

CSS

#topLink {
    position: fixed;
    bottom: 40px;
    right: 40px;
    background: rgba(72,72,72,1);
    width: 50px;
    height: 50px;
    display: none;
    text-decoration: none;
    -webkit-border-radius: 35px;
    -moz-border-radius: 35px;
    border-radius: 35px;
    -webkit-transition: all 0.3s linear;
    -moz-transition: all 0.3s ease;
    -ms-transition: all 0.3s ease;
    -o-transition: all 0.3s ease;
    transition: all 0.3s ease;
}

BindingHandler

ko.bindingHandlers.topScroll = {
    update: function (element, valueAccessor) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.

        var value = valueAccessor();

        if (ko.unwrap(value)) {

            $(element).css("display", "block");
        }
    }
};

My aim is to display the back to top style link once the topscroll is beyond a particular value. Could someone point out where I am going wrong please?


Solution

  • I've found a solution I'm happy with prior to seeing the answer here from Jeroen. I have passed a fixed true to the BindingHandler data-bind.

    <a href="javascript:void(0);" id="topLink" data-bind="topScroll: true"><i class="glyphicon glyphicon-stats"></i></a>
    

    And then amended the BindingHandler to the following...

    ko.bindingHandlers.topScroll = {
        init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            // This will be called when the binding is first applied to an element
            // Set up any initial state, event handlers, etc. here
            $(window).scroll(function() {
    
                if ($(this).scrollTop() >= 150) {         // If page is scrolled more than 150px
    
                    $(element).css("display", "block");  // show the arrow
                } else {
                    $(element).css("display", "none");   // don't show the arrow
                }
            });
    
            $(element).click(function () {      // When arrow is clicked
                $('body,html').animate({
                    scrollTop: 0                       // Scroll to top of body
                }, 'slow');
            });
    
        }    
    };