JQuery_ Novice to Ninja - Earle Castledine [90]
init: function() {
var _gallery = this;
$(this.container).scroll(function() {
_gallery.checkScroll();
});
this.load();
},
We keep a local reference to the gallery object again, so it’s available inside our event handler.
As you might remember from Chapter 3, the scroll event will notify us anytime the user moves the scroll bar:
chapter_06/11_endless_scrolling/script.js (excerpt)
checkScroll: function() {
var gallery_div = $(this.container);
if (gallery_div[0].scrollHeight - gallery_div.height() -
↵gallery_div.scrollTop() <= 0) {
this.load();
}
}
Our checkScroll function looks a bit complex at first, but there’s really little to it. We’re going to be messing around with the gallery’s containing object quite a bit in this function, so we store a reference to it to avoid running the same selector over and over. (This would lead to a significant performance hit—especially as jQuery will generate lots of events whenever the user scrolls the scroll bar.)
Next, we do some math to determine whether the scroll bar has hit the bottom yet. For this we’ll need to break out of jQuery for a bit and deal with some plain old JavaScript. The scrollHeight property is a nonstandard JavaScript property that’s nonetheless supported by all major browsers. It tells us the total scrollable height of an element, unlike height, which only tells us how much vertical space the element occupies on the page. In order to access it, we need to pull the raw DOM node from the jQuery object; the shortcut for this is [0].
By subtracting the element’s height and the current scrolling position from this scrollHeight property, we’ll determine how far from the bottom of the element the user is scrolled to. If this equals 0, the scroll bar is resting at the bottom, and we can load the images.
But what happens if the user starts scrolling up and down like a crazy person? Will we start firing off requests willy-nilly? We sure will! And as the requests start returning, our code will start adding in images—lots of them! That may be a little inappropriate for our gallery control, so as a final touch let’s build in a small safeguard.
We’ll add a Boolean property to our GALLERY object called running. When we’re about to load some data, we’ll first check that the running variable is set to true. If it is, this means an Ajax call is currently underway, and we won’t start another one: we’ll just return. If it’s false, we’ll go ahead with our call, but first set it to true.
Finally, when the request is over (successful or not), we reset the running variable to false, ready to start all over again:
chapter_06/11_endless_scrolling/script.js (excerpt)
var GALLERY = {
running: false,
…
load: function() {
// Don't call if we're already running!
if (this.running) {
return;
}
this.running = true;
var _gallery = this;
$.ajax({
…
complete: function() {
_gallery.running = false;
}
});
}
};
Keeping Context
So far we've been ensuring we can access the gallery object by storing it in a variable, with var _gallery = this;. But if you’re comfortable with keeping track of any scope changes yourself then there is a nicer way: the ajax action has an option called context that allows you to set the scope and avoids the need to keep a local reference:
var GALLERY = {
url: "getImages",
load: function() {
$.ajax({
type:"get",
url: this.url,
context: this,
success: function(data) {
// "this" now refers to the GALLERY object!
alert('loaded ' + this.url);
}
});
}
};
This makes your code neater and shorter—but you have to be aware that the scope is being modified by jQuery in the function callbacks. Other code (such as the $.each loop which displays the images) will still obey the regular JavaScript scope rules, so for those you’ll still have to keep your own reference. The context option doesn’t have to be a custom object as shown above—it can also be a jQuery or DOM object:
$("
$.ajax({
type: "get",
url: "GetResults.html",
context: $("#result"),
success: function(data)