Saturday, September 22, 2012

jQuery mobile image gallery

I started playing around with jQuery mobile and i think its great!
anyway i needed a simple image gallery for this small app and found the
following tutorial: jQuery mobile gallery which is nice and great to start with.
but the code is not that good... (js code) i didn't like things like:
code duplication, duplicate selectors, being just functions and not an object, and the fact that the selected image and first and last image is being handled by giving classes to elements on your screen. that is really bad in my book.

anyway i did a little re-factoring/changes and thought, why not share?

* note: blogger keeps adding values to the href of anchors with a hash tag. don't forget to remove them, and keep just the hash tag like: #imgshow

so this is what i did
the HTML looks like this:

the gallery itself



the dialog (should be placed outside you page content tag i have put it in the master layout)



just add this two to your view (html page) and you will be fine.

and a simple css (didn't change):

.gallery_content a img { height:80px; width:80px;
    padding:3px;
    background-color:#222;
}
 
#prevbtn, #nextbtn {
    margin:10px 15px;
}

now for the interesting part... our JavaScript!
so lets break it down.

first part, initializing the gallery:

the old code looked like this:

$('.gallerycontent img').bind('tap',function(){
  var src = $(this).attr("src");
  var alt = $(this).attr("alt");
  $('#dialogcontent').empty().append('' );
  $('#dialoghead').empty().append('

' + alt + '

' ); $(this).parent().addClass('selectedimg'); });

The new re-factored init method will look like this:

var self = this;
    var allImages = null;
    var currentImage = null;

    function init() {
        allImages = self.getImages();
        allImages.bind('tap',function(){
            switchImages ($(this));
        });

        self.bindEvents();
    }
    
    this.getImages = function () {
        return $('#galleryContent img');
    }


Now 2 functions to show the next and previous images

function switchImages (imgToSwitch) {
   var src = imgToSwitch.attr("src");
   var alt = imgToSwitch.attr("alt");
        
   currentImage = imgToSwitch;
   // insert the image to the dialog's body 
   $('#dialogcontent').empty().append('' );
   // change the dialog header text
   $('#dialoghead h2').text(alt);
}

this.goNext = function () {
    // check if the current image is the last image if so get the first image
    // else just get the next image
    if (currentImage.is(allImages.last())) {
        var next = allImages.first();
    } else {
        var next = currentImage.parent().next().find("img");
    }
 
    switchImages(next);
}

this.goPrev = function () {
    // check if the current image is the first image if so get the last image
    // else just get the previous image
    if (currentImage.is(allImages.first()))
        var prev = allImages.last();
    else            
        var prev = currentImage.parent().prev().find("img");

    switchImages(prev);
}


the old next and prev functions from that tutorial were complete "copy paste" of the same code in the init function. instead of just extracting that logic to a function.

Finally handling the events for the gallery

old code from tutorial:

$('#nextbtn').bind('tap',function(event, ui){
    gonext();
});
 
$('#imgshow').bind('swipeleft',function(event, ui){
    gonext();
});
 
$('#prevbtn').bind('tap',function(event, ui){
    goprev();
});
 
$('#imgshow').bind('swiperight',function(event, ui){
    goprev();
});



New code: (no need for that empty anonymous functions)

this.bindEvents = function () {
    $('#nextbtn').bind('tap', self.goNext);
    $('#imgshow').bind('swipeleft', self.goNext);
    $('#prevbtn').bind('tap', self.goPrev);
    $('#imgshow').bind('swiperight', self.goPrev);
}


So.. after all the code changes we now have an object not just a bunch of functions , we eliminated the code duplicates and the coupling of logic with UI (the first, last and current image was determined by giving a class to that element) 

This is the complete JS code, just put it in you .js file and you can create an instance of it at document ready event.

var page = {};

$(document).bind("pageinit", function() {
    // creating a new instance of gallery
    page.gallery = new gallery();
});

function gallery () {
    var self = this;
    var allImages = null;
    var currentImage = null;

    function init() {
        // selecting all images just once.
        allImages = self.getImages();
        // add the event for each image in our gallery
        allImages.bind('tap',function(){
            var currImg = $(this);
            switchImages (currImg);
        });

        self.bindEvents();
    }
    
    this.getImages = function () {
        // selector for all gallery images
        return $('#galleryContent img');
    }

    this.bindEvents = function () {
        // events for our gallery buttons 
        $('#nextbtn').bind('tap', self.goNext);
        $('#imgshow').bind('swipeleft', self.goNext);
        $('#prevbtn').bind('tap', self.goPrev);
        $('#imgshow').bind('swiperight', self.goPrev);
    }
    
    function switchImages (imgToSwitch) {
        // just switching the old image the new one
        var src = imgToSwitch.attr("src");
        var alt = imgToSwitch.attr("alt");
        
        currentImage = imgToSwitch;
        $('#dialogcontent').empty().append('' );
        $('#dialoghead h2').text(alt);
    }

    this.goNext = function () {
        // check if the current image is the last image if so get the first image
        // else just get the next image
        if (currentImage.is(allImages.last())) {
            var next = allImages.first();
        } else {
            var next = currentImage.parent().next().find("img");
        }
 
        switchImages(next);
    }

    this.goPrev = function () {
        // check if the current image is the first image if so get the last image
        // else just get the previous image
        if (currentImage.is(allImages.first()))
            var prev = allImages.last();
        else            
            var prev = currentImage.parent().prev().find("img");

        switchImages(prev);
    }    

    init();
}

this final JS code along with the short HTML and css will give you a pretty descent gallery for your jQuery mobile app.


enjoy!



No comments:

Post a Comment