jQuery: Firing an AJAX event local to the element that is loading data - ajax

I've been playing around with subscribing elements to AJAX events in jQuery.
I have an element that I am using to load AJAX response's. This element is only displayed IF there is data pertinent to the current context of the program.
So, I thought it would be nice and easy to .show() whenever an AJAX request has completed on it and hide it when I need to. I would like to remove the need to implicitly .show() the element every time I make an AJAX request.
In jQuery there is .ajaxSuccess() and .ajaxComplete(). These however, will fire when any AJAX request completes/succeeds, so when loading data in other parts of the page, my hidden element will .show().
The solution seems to be (per. the jQuery API reference) to use the ajaxOptions parameter in your event handler function:
$('.log').ajaxComplete(function(e, xhr, settings) {
if (settings.url == 'ajax/test.html') {
$(this).text('Triggered ajaxComplete handler.');
}
});
What I don't understand is the reason for registering an event handler for all AJAX requests to a specific element, besides being able to use $(this). Am I missing something, can I register an event handler for an AJAX request specific to an element?
If not, is there any event driven alternative to using the .url? The reason I ask is that I use the page fragment extensively for tracking page state and it would be easier to have an event handler .show() my element whenever an AJAX request loads data into it.
EDIT: Post title grammar.

My thinking, is that you want something like this:
$(document).ajaxComplete(function(e, xhr, settings) {
if(settings.url == 'ajax/test.html') {
$('#foo').text('Triggered ajaxComplete handler.');
} else if(settings.url == 'ajax/another.html') {
$('#bar').text('Triggered ajaxComplete handler.');
}
});
Does that make sense, or am I completely missing the point?

Bind a global event handler to AJAX requests and then use the event target member to decide to show elements:
$(document).ajaxSuccess(function (event, xhr, settings) {
if ($(event.target).is('#main'))
$('#main').show();
});
Would be nice to be able to fire on AJAX requests that only target specific elements, but there doesn't seem to be a way.
EDIT: Syntax

Related

How to trigger unobtrusive javascript when the content is dynamic with ajax (Lightbox)

I've got some links coming in from ajax that need lightbox functionality:
<img src='...'>
Normally this is given behavior via an on page load handler, but since the content is coming from ajax, the UJS isn't getting triggered.
Any way to do this?
If the content is coming from AJAX, then din't setup the event handling during page load. Instead, let the event bubble to the topmost container that is not being changed or replaced by AJAX. Worst case, use document as the topmost node.
$('<root element selector>').on('click', 'a.lightbox', function() {
// activate lightbox on the clicked element.
});
I'm not sure how you're triggering the ajax requests, but if it's with jQuery which seems likely, you can bind the lightbox in the success callback:
$.ajax({
url: '/route',
success: function (response, status) {
$('.lightbox').lightbox();
}
});
You can pass in a context to the jQuery selector so you don't re-attached the lightbox to links that are already in the page, for example if your ajax call is adding the links to a div with id 'lightbox_links', use this selector instead:
$('.lightbox', '#lightbox_links').lightbox();

MVC3 WebGrid: When sorting or paging, is there a way to call a javascript method BEFORE the Controller Action method is called?

I've been using this link as a reference for developing my WebGrid (http://msdn.microsoft.com/en-us/magazine/hh288075.aspx).
Currently what is happening is that my WebGrid is loaded, and I'm able to asynchronously page and sort just fine...no problems. What is an irritation is that once I click to page or sort, the user isn't aware that anything is happening.
So what I'm looking for is a way to call a javascript function (or anything really) before the controller's action method is called, so that I have something appear to let the user know work is being done to return their next page, sort, and so forth.
I'm not sure if I'm just missing something, but any help would be appreciated.
You could use the .ajaxSend() and .ajaxComplete() methods to show and hide some spinner during the AJAX requests:
$(function() {
$('#grid').ajaxSend(function () {
// this will be called before the AJAX request is sent
// here you can show some spinner
$('body').append('<div id="spinner">Loading ...</div>');
}).ajaxComplete(function () {
// this will be called after the AJAX request completes and
// could be used to hide the spinner
$('#spinner').remove();
});
});

how does jquery's promise method really work?

I don't really understand what delegate and promise are.
According to the docs -
delegate would bind a selector and event to some sort of wrapping container that can be used again at a later time for current and future items.
promise() would remap things back to when it was first bounded if everything newly loaded matches. Maybe I don't really understand this promise method.
What if the wrapper is still there, but the contents in the wrapper container have changed, and/or reloaded via Ajax? Why is it that the events are not triggering or working as it would the first time it is bound?
And yes, I have been to the docs page, I just don't understand their explanations completely.
I'm a bit confused by this question. I think this is because you are confused by promise and delegate. They are in fact completely unrelated features of jQuery. I'll explain each separately:
delegate
delegate is a feature of jQuery that was introduced in jQuery 1.4.2. (It is a nicer approach to the live feature that was added in jQuery 1.3). It solves a particular problem that comes with modifying the DOM, and particularly with AJAX calls.
When you bind an event handler, you bind it to a selection. So you might do $('.special').click(fn) to bind an event handler to all the members of the special class. You bind to those elements, so if you then remove the class from one of those elements, the event will still be triggered. Inversely, if you add the class to an element (or add a new element into the DOM), it won't have the event bound.
There is a feature of Javascript that mitigates this called "event bubbling". When an event is triggered, first the browser notifies the element where the event originated. Then it goes up the DOM tree, and notifies each ancestor element. This means that you can bind an event handler on an element high up the DOM tree, and events triggered on any child elements (even those that don't exist when the handler was bound).
delegate is jQuery's implementation of this. First, you select a parent element. Then you specify a selector – the handler will only be run if the originating element matches this selector. Then you specify an event type, such as click, submit, keydown, just as with bind. Then finally you specify the event handler.
$('#containingElement').delegate('a.special', 'click', function() {
alert('This will happen on all links with the special class');
});
promise
promise is another relatively recent addition to the jQuery featureset. It is part of the Deferred concept that was introduced in jQuery 1.5. (I think the similarity in sound between "deferred" and "delegate" is probably the source of confusion.) This is a way of abstracting away the complications of asynchronous code. The best example of this is with AJAX calls, as the object returned by $.ajax is a Deferred object. For instance:
$.ajax({
url: 'somepage.cgi',
data: {foo: 'bar'}
}).done(function() {
// this will be run when the AJAX request succeeds
}).fail(function() {
// this will be run when the AJAX request fails
}).always(function() {
// this will be run when the AJAX request is complete, whether it fails or succeeds
}).done(function() {
// this will also be run when the AJAX request succeeds
});
So it is in many ways the same as binding success handlers in the $.ajax call, except that you can bind more than one handler, and you can bind them after the initial call.
Another time when it would be useful to deal asynchronously is with animations. You can provide callbacks to functions, but it would be nicer to do this with similar syntax to the AJAX example I've provided above.
In jQuery 1.6, this functionality was made possible, and promise is part of this implementation. You call promise on a jQuery selection, and you'll get an object that you can bind event handlers to, when all the animations in the object have completed.
For instance:
$('div.special').fadeIn(5000).promise().then(function() {
// run when the animation succeeds
}).then(function() {
// also run when the animation succeeds
});
Again, this is similar in effect to traditional methods, but it adds flexibility. You can bind the handlers later, and you can bind more than one.
Summary
Basically, there is no significant relationship between delegate and promise, but they're both useful features in modern jQuery.

How do I detect the start of a ajax call?

In JQtouch, any link is automatically convert into ajax call. I want to detect the moment the ajax call was send. This is so that i could insert a loading screen to let users know that the system is processing the submission.
I search through jqTouch API and apparently they only have callback events for page animation. Am i missing out on anything?
You can use the core jQuery global AJAX functions, for example $.ajaxStart() for the start of a batch of requests, or $.ajaxSend() to detect the beginning of each request. Something like this:
$(document).ajaxSend(function() {
alert("Request sending...");
});
Ready up on jQuery's Ajax Events: http://docs.jquery.com/Ajax_Events .
You may bind these to elements as follows:
$("...").bind("ajaxSend",myFunction) ;
every element specified this way will then react to a Ajax call being made with the specified callback function.

Bind custom event handler after ajax load

Specifically I'm looking to bind lightbox to a specific element. Normally I would just do this: $('a.lightbox').lightBox(); but that isn't working since I'm doing some loading with AJAX. Looking at the jQuery API I found .bind() and .live() but I'm not getting anything when I do $('a.lightbox').bind('lightBox') after the AJAX .load() call.
What am I missing?
You need to add a callback function that handles that.
$("#div").load(url, {}, function(){ $('a.lightbox').lightBox(); });
Bind isn't going to help you, as the event isn't getting an event fired on it.
Another way would be to bind to an element higher up in the dom and check the target type. Such as:
$('#div').bind('click', function (event) {
target = $(event.target);
if (target.hasClass('lightbox')) {
// do stuff here
}
});
Just don't go too far up or you'll be catching way too many clicks.

Resources