Tyler Sloan
Tyler Sloan

Reputation: 246

Create object instances inside each loop

I am trying to get more object-oriented when writing Javascript for (simple) websites. I want to create a new object, vidyo, for each video element on the page while looping through them. Here's what I have right now. This achieves my goals for the function but I know there has to be a better way to organize this code.

I want to be able to call vidyo on $('video') after the loop. I also want to make it more plugin like, so I could possibly add in options.

I tried making vidyo a legitimate object and tried making new instances of it inside the loop but that didn't work.

Any pointers on how to turn these lines into something more robust? Thanks.

var $win = $(window),
    top = $win.scrollTop(),
    $videos   = $('video');

var vidyo = {
    play: function(video) {
        video[0].play();
    },
    pause: function(video) {
        video[0].pause();
    },
    check: function(vid) {
        var top = $win.scrollTop();
        var videoHeight    = $(vid).outerHeight(true),
            videoHitTop    = $(vid).offset().top,
            videoOffTheTop = videoHeight + videoHitTop;

        if ( top >= videoHitTop && top <= videoOffTheTop ) {
            vidyo.play($(vid));
        } else {
            vidyo.pause($(vid));
        }
    }
}

var checkVideoPosition = function() {
    $videos.each( function( index, el ) {
        vidyo.check(el);
    })
}

$win.on('scroll', checkVideoPosition);

Upvotes: 2

Views: 154

Answers (2)

Tomalak
Tomalak

Reputation: 338406

Remove all global variables and keep it simple. You don't really need a plugin or a fancy object oriented approach.

$(window).on('scroll', function () {
    var top = $(this).scrollTop(),
        $videos = $('video'),
        $inView = $videos.filter(function () {
            var height = $(this).outerHeight(true),
                hitTop = $(this).offset().top,
                offTheTop = height + hitTop;
            return top >= hitTop && top <= offTheTop;
        });
    $inView.each(function () {
        if (this.paused) this.play();
    });
    $videos.not($inView).each(function () {
        if (!this.paused) this.pause();
    });
});

Edit: you can make this a bit nicer by defining the fixed utility functions in a closure. This way the functions are not re-defined every time the scroll event is being triggered.

$(window).on('scroll', (function () {
    function isInView() {
        var top = $(window).scrollTop(),
            height = $(this).outerHeight(true),
            hitTop = $(this).offset().top,
            offTheTop = height + hitTop;
        return top >= hitTop && top <= offTheTop;
    }
    function playConditionally() {
        if (this.paused) this.play();
    }
    function pauseConditionally() {
        if (!this.paused) this.pause();
    }
    return function () {
        var $videos = $('video'),
            $inView = $videos.filter(isInView);
        $inView.each(playConditionally);
        $videos.not($inView).each(pauseConditionally);
    };
})());

Upvotes: 1

DRAB
DRAB

Reputation: 445

MDN has an extremely well-written guide to Object Oriented Programming in Javascript. The links along the left are also very helpful pages to read too. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

Here's a template to get you started. I won't re-write all your functions for you, I merely intend to steer you in the right direction.

function Vidyo (el) {
    this.element = el && el.tagName === "VIDEO" ? el : document.createElement("video");
}

Vidyo.prototype = {

    play: function() {
        this.element.play();
    },

    pause: function () {
        this.element.pause();
    },

    check: function () {
        // ...
    }
}

var $videos = $("video"),
    vidyos = [];

$videos.each(function (i, el) { vidyos.push( new Vidyo(el) ); });

Hope this helps. I don't know if jQuery has an easier way to get this set up -- I've never used the library. Good luck and have fun!

Upvotes: 1

Related Questions