DotNetCurry Logo

Create a Responsive jQuery Flickr Image Gallery with Lazyloading

Posted by: Irvin Dominin , on 6/2/2015, in Category jQuery and ASP.NET
Views: 10119
Abstract: This article uses jQuery and Lazyloading to load images from Flickr and display it in a gallery using responsive design.

Flickr is a popular photo-sharing site and provides a couple of ways to retrieve photos and related information. The Flickr Feed Service allows you to get a listing of the 20 most recent photos from a particular person or a particular group. To access photos from user accounts, you can use http://api.flickr.com/services/feeds/photos_public.gne . Once you know which type of photo feed you’d like, you can search for tags on that Flickr’s public photo feed . A tag is a word or short phrase that the photo owner uses to describe an element of the photo. In the url, add the tag keyword to the URL to specify a tag; for example: &tags=nature

The Flickr photo feed service can return photo information in many different formats like RSS, Atom, CSV, and JSON. We want data in JSON format, so we will add &format=json to the query string.

Finally, in order to successfully request JSON data from another website, we will add one last bit to the URL: &jsoncallback=?. For security reasons you can’t send an XMLHTTP request to a different domain. To get around that problem, we use the &jsoncallback=? piece to notify the external wesbite that we want to receive JSONP data. Internally jQuery’s $.getJSON() function treats this request as if the web browser was requesting an external JavaScript file and thus makes the call successful.

So our request url will be similar to the following:

'http://api.flickr.com/services/feeds/photos_public.gne?tags=nature&tagmode=any&format=json&jsoncallback=?’

With this information under our belt, let's request a collection of photos from Flickr and display them on a page. We will use Twitter Bootstrap to make our page Responsive Design enabled.

We will also be using Lazy Loading. Lazy Loading is delaying the loading of images, particularly in long web pages that has a lot of images. Images outside of the viewport are not loaded, until the user scrolls to them. This makes the page load faster and also reduces the load on the server, by not requesting all the images at one go.

Create a new file ‘FlickrLazyload.html’ and an ‘Images’ folder. To begin with, we will need a simple <div> as follows:

<body>
    <div class="flickr" />
</body>

For layout purpose, this example uses css kept in Images/css/flickr.css

Consider the following piece of code. I have added some comments in the code to help you understand what’s going on:

$(function () {

    // When the page is scrolled call the lazyLoadImage function
    $(window).scroll(lazyLoadImage);

    var imageList='';
                
    // Get the photo feed from flickr
$.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?tags=nature&tagmode=any&format=json&jsoncallback=?', function(data) {
        // Loop through the flickr json response
        $(data.items).each(function(i, item) {
            // Create a new figure element with an img element with:
            //     - class "lazy"
            //     - the current src as a loding gif
            //     - the data-src with the real flickr image path
            // Create a figcaption element with the image title
            imageList+='<div class="col-md-4"><figure><div class="imgWrap">
<img class="lazy" src="images/ajax-loader_b.gif" 
data-src="'+item.media.m+'"/></div> <figcaption>'+item.title+'</figcaption></figure></div>';                        
        });
                    
        if (imageList=='') {
            $(".flickr").html("Error");
            return
        }
                    
        // Append the newly created element list
        $(".flickr").append(imageList);
                        
        // Wrap every three elements in a div row for scaffolding purposes
        var $images = $(".flickr .col-md-4");
        for(var i = 0; i < $images.length; i+=3) {
            $images.slice(i, i+3).wrapAll("<div class='row'></div>");
        }
                    
        // After the flickr response call the lazyLoadImage function
        lazyLoadImage();
    });
             
});

The lazyLoadImage() function which we will define shortly, is called on the page scroll.

$(window).scroll(lazyLoadImage);

We use $.getJSON to fetch data from the flickr service.

$.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?tags=nature&tagmode=any&format=json&jsoncallback=?', function(data) { }

We then loop through the response and create a new <figure> for each element.

$(data.items).each(function(i, item) {
    // Create a new figure element with an img element with:
    //     - class "lazy"
    //     - the current src as a loding gif
    //     - the data-src with the real flickr image path
    // Create a figcaption element with the image title
imageList+='<div class="col-md-4"><figure><div class="imgWrap"><img class="lazy" src="images/ajax-loader_b.gif" data-src="'+item.media.m+'"/></div> <figcaption>'+item.title+'</figcaption></figure></div>';                        
});

Each figure element is structured with:

1. "lazy" class

2. the current src attribute as a loading gif image

3. the data-src attribute with the real flickr image path

and a <figcaption> element with the image title displayed below the respective image.

The next step is to check if imageList is empty. If it is, display an error message to the user. Finally, we append the images to the flickr div outside the loop.

if (imageList=='') {
    $(".flickr").html("Error while loading images");
    return
}
                    
// Append the newly created element list
$(".flickr").append(imageList);

Observe that we are only constructing the string inside the loop and not appending it to the imagelist. A common mistake made by developers is to call append inside every loop. We are using append() outside the loop to improve performance.

For scaffolding purposes, we are using the Twitter Bootstrap plugin, so that the images are organized three per row using col-md-4 and row classes.

var $images = $(".flickr .col-md-4");
for(var i = 0; i < $images.length; i+=3) {
    $images.slice(i, i+3).wrapAll("<div class='row'></div>");
}
                    
lazyLoadImage();

And finally, with the flickr div filled with our structure, we call the isVisible function and lazyLoadImage function which are defined as:

// Check if the requested element is 
// COMPLETELY visible in the user viewport
function isVisible($element)
{
    // Get the current page visible area in the user screen
    var topView = $(window).scrollTop();
    var botView = topView + $(window).height();
    var topElement = $element.offset().top;
    var botElement = topElement + $element.height();                
    return ((botElement <= botView) && (topElement >= topView));
}

function lazyLoadImage(){
    // Loop through the images not already loaded, with "lazy" class
    $('.flickr img.lazy').each(function(){
        // Check if the element is visible in the viewport
        if (isVisible($(this).closest('.imgWrap'))) {                
            // If the element is visibile,
            // set the img src as its data-src attribute, 
            // remove the lazy class 
            // and remove the data-src attribute
            $(this).one("load", function() {
                // image loaded here
                $(this).removeClass('lazy');
            }).attr('src', $(this).attr('data-src')).removeAttr('data-src');                        
        }
    });
};

In our example, we are loading 20 images which are divided across 7 rows, with 3 images each in a row. While scrolling the page, in the lazyLoadImage() function, we loop through the images which are not already loaded (recognized by the "lazy" class). We then use the isVisible() function defined by us to check if the requested element is completely visible in the user viewport i.e. if the user has scrolled down further. If the element is visible in the user viewport that means it’s time to display the image to the user; so we switch the data-src attribute with the src attribute. Remember the data-src contains the gif preloading image, while the src attribute contains the path to the actual flickr image. This switch causes the browser to download and display the real image.

Save and browse ‘FlickrLazyload.html’ in your browser and you will see a Flickr image gallery powered with Lazy Loading. The images will load as you scroll down the page.

 

s2-flickr-gallery

This code was authored by Irvin Dominin and explained by Suprotim Agarwal

Live Demo: http://www.jquerycookbook.com/demos/S6-Images/52-FlickrLazyload.html

If you liked this article, take a look at a new jQuery book The Absolutely Awesome jQuery Cookbook which contains scores of practical jQuery/jQueryUI recipes you can use in your projects right away.

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on Google+
Further Reading - Articles You May Like!
Author
Irvin Dominin is currently working as lead of a technical team in SISTEMI S.p.A. (Turin, Italy) on .NET, jQuery and windows Projects. He is an active member on StackOverflow. You can reach him at: irvin[dot]dominin[attherate]gmail[dot]com or on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!