How to know which element in body triggered AJAX request in jQuery
I'm working on an app and trying to use the Facebook behavior for an AJAX request. In Facebook you get a nice loading image next to the icon which triggers the AJAX request. Well, it's pretty simple to implement if you have 1-2 elements in the page.
I want to make it generic and would like that whenever any element triggers an AJ开发者_StackOverflow社区AX request, I want to show a small GIF next to it. For this, I thought the AjaxSend event of jQuery would be good enough, but alas it doesn't give me a handle of the object which triggered the AJAX call. I would like to know if it is possible via some method of jQuery to know which element triggered the AJAX call and also to get the same handle when the AJAX call is completed.
If you feel my approach to the problem is not correct, I would love to hear your suggestions.
Another generic way that requires least setup is to use activeElement
property of the event target:
$(document).ajaxStart(function (e) {
try {
var $el = $(e.target.activeElement);
var isButton = $el.hasClass('btn');
// just a precautionary check
if (!isButton) {
return;
}
$el.button('loading'); // or whatever else you want to do
} catch (ex) {
console.log(ex);
}
});
$(document).ajaxStop(function (e) {
try {
var $el = $(e.target.activeElement);
var isButton = $el.hasClass('btn');
if (!isButton) {
return;
}
$el.button('reset');
} catch (ex) {
console.log(ex);
}
});
The reason this works is because when a button is clicked, it receives focus. And e.target
(which is document
at this point tells us about the current element in focus via activeElement
property.
Note that the try...catch
is completely optional. It is usually a good idea to wrap any global handlers in try...catch
just to ensure that any exception here doesn't cause any side-effects. The console.log
will let you know about the exception, if any, so that you can fix it later.
If you want to use the ajax request handlers, an id will need to be assigned (manually or automatically) to the element that triggered the event. You could then send this id as an additional key-value pair in the request (element_id:THEID) and grab it with various substring methods in the ajax request handlers.
Example:
<script type="text/javascript">
$(document).ready(function(){
$("input").click(function(){
var newid = (create a custom id with date and time);
$(this).attr("id", newid);
$.post("handler.php", {element_id : $(this).attr("id")});
});
}).ajaxSend(function(e, xhr, settings){
var start_position = settings.data.indexOf("element_id");
var equalsign_position = settings.data.indexOf("=", start_position);
var ampersand_position = settings.data.indexOf("&", start_position);
var element_id;
if(ampersand_position == -1){
element_id = settings.data.substr(equalsign_position+1);
} else {
element_id = settings.data.substr(equalsign_position+1, ampersand_position-equalsign_position-1);
}
$("#"+element_id).after("<div id='div"+element_id+"'><img src='loading_start.png' /></div>");
}).ajaxComplete(function(e, xhr, settings) {
var start_position = settings.data.indexOf("element_id");
var equalsign_position = settings.data.indexOf("=", start_position);
var ampersand_position = settings.data.indexOf("&", start_position);
var element_id;
if(ampersand_position == -1){
element_id = settings.data.substr(equalsign_position+1);
} else {
element_id = settings.data.substr(equalsign_position+1, ampersand_position-equalsign_position-1);
}
$("#div"+element_id).remove();
});
</script>
<input type="button" value="Save" />
The alternative is handling the appearing and disappearing of the loading image in each event handler (but I seem to understand you have too many of them?), like this:
<script type="text/javascript">
$(document).ready(function(){
$("input").click(function(){
var element_id = (generate custom id);
$(this).after("<div id='div"+element_id+"'><img src='loading_start.png' /></div>");
$.post("handler.php", {var:"hello"}, function(){
$("#div"+element_id).remove();
});
});
})
</script>
I was also trying to catch the ajax event to animate some buttons, and I came up with:
$j('.btn').bind('click',function(){
triggerElement = $j(this);
});
$j(document).ajaxSend(function(event,xhr,options){
var userAgent = $j.browser;
if (userAgent.mozilla)
triggerElement = $j(event.target.activeElement);
if (triggerElement && triggerElement.is('.btn')){
var triggerOffset = triggerElement.offset();
genericDisabler = $j('<div></div>');
genericDisabler.addClass('generic-disabler');
$j('body').append(genericDisabler);
genericDisabler.width(triggerElement.outerWidth());
genericDisabler.height(triggerElement.outerHeight());
genericDisabler.offset({
left:triggerOffset.left,
top:triggerOffset.top
});
triggerElement.switchClass('orange','gray-ajax-gradient',25).animate({
opacity: 0.6
});
}
});
$j(document).ajaxComplete(function(event,xhr,options){
if (triggerElement && triggerElement.is('.btn')){
triggerElement.switchClass('gray-ajax-gradient','orange',25,function(){
if (genericDisabler)
genericDisabler.remove()
}).animate({
opacity: 1
});
}
triggerElement = null;
});
So I make sure I get the element where the click is done, but I keep the reference to what FF can do well.
I have faced the same problem before...well it will not give u handle, see if below code is useful to u or not. here is my solution
$(document).click(function(event){
if(event.target.id != "comment" && event.target.id != "fb-button"){
$("#submit-button").css("display","none");
if($("#comment").val() == ""){
$("#comment").addClass("lightText").val("write a comment...");
}
}
});
just track all the click events on body and get its source
I had same problem, what I did was setting a global parameter and set the clicked button to it:
var btn = null;
$(document).ajaxSend(function(event, xhr, settings) {
btn.find(".ui-button-text:first").append('<div class="loading"></div>');
}).ajaxComplete(function(event,request, settings) {
$(".loading").remove();
});
just add a style for the loading and it will add a loading indicator to Jquery UI buttons.
<style type="text/css">
.btn {
margin: 5px 10px 0 0;
}
.loading {
display: inline;
background: url(../images/loading.gif) center no-repeat;
margin: 0 0 0 5px;
padding: 0 0 0 16px;
}
</style>
Quite a lot of approaches how to solve this problem.
I had multiple elements that can trigger an AJAX event and want to do some automatic callbacks each time an AJAX request is sent and completed. But only on the element that has triggered it.
I ended up wrapping up the $.get() method into my own object:
var AJAX = {
fetch: function (url, data, targetObj) {
var oldText = ''
targetObj = (this.isDefined(targetObj) ? targetObj : null)
if (targetObj) {
oldText = targetObj.text()
targetObj.text('Loading...')
}
return $
.get(url, data)
.always(function () {
// if target object is provided, run end callbacks on it
if (targetObj) {
targetObj.text(oldText)
}
})
}
}
Then calling it like this:
AJAX.fetch('my_script.php', {somedata: 'blabla'}, $(this))
You can completely generalize it so it can run any callback you add there + logs errors automatically. I wrote a tutorial how to achieve that + you can find the code on GitHub.
$(document).ajaxStart( function(e) {
var el = e.target.activeElement.id;
alert('event triggerd by : ' + el);
});
Main Solution : e.target.activeElement.id
This works for me:
$(document).ajaxSend(function (e, jqXHR, ajaxOptions) {
try {
if (e.target.activeElement) {
var $el = $(e.target.activeElement);
var isButton = $el.hasClass('btn');
if (!isButton) return;
$el.prop('disabled', true);
jqXHR.complete(function () {
$el.prop('disabled', false);
});
}
} catch (ex) {
console.log(ex);
}
});
精彩评论