damiano celent
damiano celent

Reputation: 709

How to apply a function to a selected element, coverting Jquery code to JS and getting type error

I am trying to change a Jquery function to vanilla JS and I have issues replicating it. I have fixed some errors it threw, but now I am entirely stuck.

The Jquery code

jQuery(window).load(function () {
    var windowHeight, windowScrollPosTop, windowScrollPosBottom = 0;

    function calcScrollValues() {
        windowHeight = jQuery(window).height();
        windowScrollPosTop = jQuery(window).scrollTop();
        windowScrollPosBottom = windowHeight + windowScrollPosTop;
    }

    jQuery.fn.revealOnScroll = function (direction, speed) {
        return this.each(function () {

            var objectOffset = jQuery(this).offset();
            var objectOffsetTop = objectOffset.top;

            if (!jQuery(this).hasClass("hidden")) {

                // if argument is "right"
                if (direction == "right") {
                    jQuery(this).css({
                        "opacity": 0,
                        "right": "700px",
                        "position": "relative"
                    });
                    // if argument is "left"
                } else {
                    jQuery(this).css({
                        "opacity": 0,
                        "right": "-700px",
                        "position": "relative"
                    });

                }
                jQuery(this).addClass("hidden");
            }
            if (!jQuery(this).hasClass("animation-complete")) {

                // if the page has been scrolled far enough to reveal the element
                if (windowScrollPosBottom > objectOffsetTop) {
                    jQuery(this).animate({"opacity": 1, "right": 0}, speed).addClass("animation-complete");
                } // end if the page has scrolled enough check
            } // end only reveal the element once
        });
    }
    function revealCommands() {
        jQuery(".title").revealOnScroll("right", 1200);
    }

    calcScrollValues();
    revealCommands();

    // run the following on every scroll event
    jQuery(window).scroll(function () {
        calcScrollValues()
        revealCommands();
    }); // end on scroll

});

This work, if you uncomment the Jquery code in the pen.

Here is the JS code

function calcScrollValues() {
    windowHeight = screen.height;
    windowScrollPosTop = document.body.scrollTop;
    windowScrollPosBottom = windowHeight + windowScrollPosTop;
};
window.onload = function () {
    var windowHeight, windowScrollPosTop, windowScrollPosBottom = 0;

    function revealOnScroll(direction, speed) {
        return this.each(function () {
            var objectOffset = this.getBoundingClientRect();
            var objectOffsetTop = getBoundingClientRect();

            if (!this.classList.contains("hidden")) {
                // if argument is "right"
                if (direction == "right") {
                    this.setAttribute('style', 'opacity:0; right:700px; position: relative');
                }
                ;
                // if argument is "left"
            } else {
                this.setAttribute('style', 'opacity:0; right:700px; position: relative');
            }
            ;
            this.classList.add("hidden");
        });
        if (!this.classList.contains("animation-complete")) {

            // if the page  scrolled far enough to reveal the element
            if (windowScrollPosBottom > objectOffsetTop) {
                this.setAttribute('style', 'opacity:1; right:0; transition: speed + "ms"');
                this.classList.add("animation-complete");

            } // end if the page has scrolled enough check

        }
        ; // end only reveal the element once
    }
}

function revealCommands() {
    document.querySelector(".title").revealOnScroll("right", 1200);
}
calcScrollValues();
revealCommands();

// run the following on every scroll event
window.addEventListener('scroll', function () {
    calcScrollValues()
    revealCommands();
});

I know that the 'return this.each(function() {}' part cannot possibly work in JS, and have no idea how to get the JS code for that.

And the other main issue is this
'document.querySelector (".title").revealOnScroll("right", 1200);' obviously gives a Type error"not a function".

There are probably even more issues with this, but this is the one which has me stuck.

Codepen:

http://codepen.io/damianocel/pen/yYKyaN

Upvotes: 0

Views: 117

Answers (1)

Marc Dix
Marc Dix

Reputation: 1969

Your original code added the revealOnScroll method to the object returned by jQuery when querying for .title (via jQuery.fn.revealOnScroll). By querying with the browser, you lost the jQuery object but got a NodeList from document.querySelectorAll('.title') instead (you shouldn't use document.querySelector as it returns only one element - this is not what you had before with jQuery). You now need to add the revealOnScroll method to the prototype of the NodeList in order to use it like you did before with jQuery.

After doing so, you hit some other problems: NodeList looks like, but is no Array and has no iterator by itself, but you can lend the one from Array.prototype.forEach.

You also lose the this binding, but using the element provided by forEach instead should just work fine.

I haven't checked the code completely. It gets interpreted without errors but I had to make some changes to it, like moving function calls inside the onload function.

Please check it line by line and report back if you encounter problems that you can't solve on your own.

function calcScrollValues() {
    windowHeight = screen.height;
    windowScrollPosTop = document.body.scrollTop;
    windowScrollPosBottom = windowHeight + windowScrollPosTop;
};
window.onload = function () {
    var windowHeight, windowScrollPosTop, windowScrollPosBottom = 0;

    NodeList.prototype.revealOnScroll = function(direction, speed) {
        Array.prototype.forEach.call(self, function (element, index) {
            var objectOffset = element.getBoundingClientRect();
            var objectOffsetTop = getBoundingClientRect();

            if (!element.classList.indexOf("hidden") !== -1) {
                // if argument is "right"
                if (direction == "right") {
                    element.setAttribute('style', 'opacity:0; right:700px; position: relative');
                };
            // if argument is "left"
            } else {
                element.setAttribute('style', 'opacity:0; right:700px; position: relative');
            };
            element.classList.add("hidden");
          
            if (element.classList.indexOf("animation-complete") === -1) {
                // if the page  scrolled far enough to reveal the element
                if (windowScrollPosBottom > objectOffsetTop) {
                    element.setAttribute('style', 'opacity:1; right:0; transition: speed + "ms"');
                    element.classList.add("animation-complete");
                } // end if the page has scrolled enough check
            }; // end only reveal the element once
        });
    }
    
    calcScrollValues();
    revealCommands();
}

function revealCommands() {
    document.querySelectorAll(".title").revealOnScroll("right", 1200);
}

// run the following on every scroll event
window.addEventListener('scroll', function () {
    calcScrollValues()
    revealCommands();
});
<div class="title" />

Upvotes: 1

Related Questions