dimsemenov / Magnific-Popup

Light and responsive lightbox script with focus on performance.
http://dimsemenov.com/plugins/magnific-popup/
MIT License
11.38k stars 3.49k forks source link

"lazy-loading" gallery items in batches #363

Open clime opened 10 years ago

clime commented 10 years ago

I have a set of images and magnific popup applied on them. I'd like to load new images when I hit the end of the list. I have come up with approximately this code:

function addItemsToPopupIfOpen(items) {
    if (!$.magnificPopup.instance) return;
    var mfp = $.magnificPopup.instance;
    items.find('a.mfp-image').each(function() { mfp.items.push(this); });
    mfp.updateItemHTML();
}

The problem is that I need to get the items by an ajax call and for that I must make magnific popup wait for it to finish. Otherwise it just jumps to the first image. Is there a way to put magnific popup into the loading state in a beforeChange event? And when the call is done to show the first of the new items..

dimsemenov commented 10 years ago

Well, you may override prev/next functions and don't fire them until data is loaded:

callbacks: {
    open: function() {
        var mfp = $.magnificPopup.instance;
        var proto = $.magnificPopup.proto;

        // extend function that moves to next item
        mfp.next = function() {
            if(ready) {
                proto.next.call(mfp);   // go to next item
            } else {
               // do something else
            }
        };

        mfp.prev = function() {
             // same for prev
        };
    }
}
clime commented 10 years ago

Ah, thanks for that! I was finally able to put it together:

callbacks: {
        open: function() {
            var mfp = $.magnificPopup.instance;
            var proto = $.magnificPopup.proto;
            var waiting_for_next_page = false;

            $(document).on('next_page_loaded', selector, function(event, items) {
                items.find('a.mfp-image').each(function() {
                    mfp.items.push(this);
                });
                mfp.updateItemHTML();
                if (waiting_for_next_page) {
                    proto.next.call(mfp);
                    waiting_for_next_page = false;
                    mfp.updateStatus('ready');
                }
            });

            mfp.next = function() {
                var moreBtn = $(selector).find('.endless_more');
                if (mfp.index < mfp.items.length-1 || !moreBtn.length) {
                    proto.next.call(mfp);
                    return;
                }
                $(mfp.content).remove();
                mfp.updateStatus('loading');
                waiting_for_next_page = true;
                moreBtn.click(); // produces next_page_loaded
            };
        },
        close: function() {
            $(document).off('next_page_loaded', selector);
        }
}

It has a feature that only clicking on "next" button can load the new images and "prev" buttons just keeps cycling in the already loaded ones. But that is acceptable for users, I hope. Thanks!

Edit: maybe I'll prevent cycling through images altogether. That will be better I guess. I just need to find out if the previously loaded batch was the last one and hide/display next button for the last image accordingly. The prev button is easy to handle.

dimsemenov commented 10 years ago

Thanks for sharing code!

dwo commented 9 years ago

This was incredibly helpful in trying to do something similar. Thank you!