2

I have 2 elements on my page that use Ajax. One is a simple checkbox (sets a default) and the other is a popup window triggered by a link. The popup window has to load a bunch of elements so I have a 'loading...' overlay div that is triggered by ajaxStart() and hidden at ajaxStop().

Everything works fine except that the ajaxStart() loading overlay is getting triggered for both the checkbox and the popup. Its annoying for the checkbox because its a quick 'flash' of the div which I don't want.

My Question: How do I ONLY trigger the AjaxStart for a particular element on the page and not every Ajax-able element on the page?


HTML

<input type="checkbox" id="defaultproject" /> <a class="openDialog" data-dialog-id="subscriberDialog" data-dialog-title="Project Subscriber" href="/Project/CreateSubscriber/1020" id="newsubscriber">Add Subscriber</a> 

Javascript

 //POPUP $(document).ready(function () { $(".openDialog").live("click", function (e) { e.preventDefault(); $("<div></div>") .addClass("dialog") .attr("id", $(this).attr("data-dialog-id")) .appendTo("body") .dialog({ title: $(this).attr("data-dialog-title"), close: function () { location.reload() }, modal: true, draggable: false, resizable: false, width: 500 }) .load(this.href); }); $(".close").live("click", function (e) { e.preventDefault(); $(this).closest(".dialog").dialog("close"); }); //CHECKBOX $("#defaultproject").change(function () { var isitchecked = document.getElementById("defaultproject").checked $.ajax({ url: '@Url.Action("SetDefaultProject")', data: {"id": ProjectId, "isitchecked": isitchecked }, type: 'POST', cache: 'false', success: function (response) { document.getElementById("defaultproject").disabled = "disabled"; }, error: function (xhr) { alert('There was an error. Please try again'); document.getElementById("defaultproject").checked = "" } }); }); //SHOW LOADING DIV //*** THIS IS WHERE I'M HAVING PROBLEMS $('.openDialog').ajaxStart(function () { $('#loadingdiv').show(); }).ajaxStop(function () { $('#loadingdiv').hide(); }); 

3 Answers 3

3

Why do you want to use an event? If it is only specific to the pop use callback functions:

$(".openDialog").live("click", function (e) { e.preventDefault(); $('#loadingdiv').show(); $("<div></div>") .addClass("dialog") .attr("id", $(this).attr("data-dialog-id")) .appendTo("body") .dialog({ title: $(this).attr("data-dialog-title"), close: function () { location.reload() }, modal: true, draggable: false, resizable: false, width: 500 }) .load(this.href,function(){ $('#loadingdiv').hide(); }); }); 
Sign up to request clarification or add additional context in comments.

3 Comments

Good solution - it does work for almost everything I need. The problem is the popup. I see the loading... div on load. However, the popup has a form that is submitted and I'd like the loading... div to also appear when that is saving the data (and pulling up the confirmation). The AjaxStart() event did give me this functionality. However, I can work around that so this might be the solution that works for me.
Okay, i think my first answer, which I have deleted after I have noticed that you are using .load on an empty div, might be helpful after all. You will need to follow certain rules though, which you are not doing currently...
@MikeSmith, okay check my other answer.
1

jQuery doesn't seem to be passing anything to ajaxStart allowing you to know what ajax request was started.

So it's probably best just to handle the distinction in your ajax call sources, rather than trying to handle it in your ajaxStart handlers.

You can achieve this through a global variable through. Declare a global variable like

 var checkBoxAjax = false; 

Then make it true before placing checkbox ajax call like

 $("#defaultproject").change(function () { checkBoxAjax = true; var isitchecked = document.getElementById("defaultproject").checked $.ajax({ url: '@Url.Action("SetDefaultProject")', data: {"id": ProjectId, "isitchecked": isitchecked }, type: 'POST', cache: 'false', success: function (response) { document.getElementById("defaultproject").disabled = "disabled"; }, error: function (xhr) { alert('There was an error. Please try again'); document.getElementById("defaultproject").checked = "" } }); 

});

and in your ajaxStart add a check like

$('.openDialog').ajaxStart(function () { if(!checkBoxAjax) $('#loadingdiv').show(); else checkBoxAjax = false; }).ajaxStop(function () { $('#loadingdiv').hide(); }); 

3 Comments

Using global variables like that is quite messy and unnecessary.
Yeah, I agree. But this seems to be the only way while using ajaxStart.
this is a good answer but i also agree that ajaxstart might be the wrong way to go.
1

The problem here is that tying an ajax call to a particular dom object is only specific to the load function or when a context is set.

As such the entire task is not deterministic. Consider the following example:

$.ajax({ url: "example.com", success: function(response) { $('.openDialog').html(response); } }); 

As the call to $.ajax does not explicity mention .openDialog anywhere within its options argument, it is impossible to tell if the success function does load html into it.

However what you could do is trigger the event whenever the context object is set. This will not be very reliable but some purposes it might be okay.

(function(ajax) { $.fn.ajax = function(options) { if (options.context) { $(options.context).trigger("ajaxLoadStart"); return ajax.apply(this, arguments).then(function() { $(options.context).trigger("ajaxLoadEnd"); }); } return ajax.apply(this, arguments); }; })($.fn.ajax); 

Now you can bind to ajaxLoadStart and ajaxLoadEnd:

$(document).on("ajaxLoadStart", ".dialog", function () { $('#loadingdiv').show(); }).on("ajaxLoadEnd", ".dialog", function () { $('#loadingdiv').hide(); }); 

(Note that $(document).on(event, selector, callback) is the same as the deprecated $(selector).live(event, callback);)

Now whenever the div with class dialog is included as context in the options object for $.ajax, it will trigger ajaxLoadStart and then ajaxLoadEnd. As far as I know, jQuery's .load() internally calls $.ajax with the context set on the respective object.

Update

Unfortunately .load doesn't use $.ajax with context. So you will need to attach the triggers to .load as well:

(function(load) { $.fn.load = function(url, params, callback) { if ( typeof url !== "string") return load.apply(this, arguments); this.trigger("ajaxLoadStart"); var done = (function(callback) { return function() { $(this).trigger("ajaxLoadEnd"); if ($.isFunction(callback)) callback.apply(this, arguments); }; })($.isFunction(params) ? params : callback); return load.call(this, url, $.isFunction(params) ? done : params, $.isFunction(callback) ? done : callback); }; })($.fn.load); 

Both of these adapters should work well for now. However if you need to revise them every time you upgrade jquery as this is prone to break (double triggering of events) if the internal workings of jquery changes.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.