How can I $ .each wait for the .trigger ('click') event to load everything?

Inside the $ .getJSON success function, I first fire the element's click event:

$('#' + data[0].ID).trigger('click'); 

The click-triggered event has its own $ .getJSON method for loading a bunch of data into a div. The next line after the event is fired:

 $.each(data[0].ListEntries, function (key, val) { //this relies on the triggered click event //having completely loaded all data! } 

At first, $ .each did not seem to do anything, but I added a warning immediately after the event triggered. After responding to the warning, the code in $ .each shows what it should.

I assume that $ .each works before the click event finishes loading the data.

setTimeout pauses long enough for the click event to load data, but I would prefer not to set an arbitrary time:

 setTimeout(function() { $.each(data[0].ListEntries, function (key, val) { //this relies on the triggered click event //having completely loaded all data! } }, 1000); 

I also tried $ .when and $, but to no avail (although adding a warning to $ .each inside $. Then creates a delay for $ .each to work):

 $.when($('#' + data[0].ID).trigger('click')).then(function () { $.each(data[0].ListEntries, function (key, val) { //this relies on the triggered click event //having completely loaded all data! }) 
+8
jquery
source share
3 answers

Emphasized for clarity.

.trigger() returns a jQuery object, so you are not $.when() ... $.then() to use $.when() ... $.then() .

On the other hand, .triggerHandler() will return an object of your choice, which allows you to do a delayed trick.

Your code is organized into three functions, simplified below. The call path is 1,2,3, and the entire important return path is 3,2,1.

(1) The highest level function (JSON success) will include the following lines:

 function() { ... $.when($('#' + data[0].ID).triggerHandler('click')).done(function() { $.each(data[0].ListEntries, function (key, val) { ... }); }); ... }; 

(2) The click handler invoked by (1) will look like this:

 $("img.Button").on("click", function () { return GetModels(this.id);//here `return` passes on the jqXHR object, up the return path. }); 

(3) And the lower level function containing JSON, on which (1) depends, will have this general form:

 function GetModels(id) { ... var jqXHR = getJSON(function(){...}); ... return jqXHR;//it is vital to retutn the jqXHR object arising from the json call. } 

Notes:

  • The return path supplies, as an argument to the promise, the .when() method in (1), the jqXHR object that arises from the call to .getJSON() in (3). Chained .done() in (1) is thus forced to wait until jqXHR is resolved (i.e. completed) before the function that is provided as an argument is run.
  • The click handler makes no assumptions about how it is called. It just returns a jqXHR object. Thus, when called with .triggerHandler() the click handler can add additional behavior to it without affecting the normal click action.
  • It would be simpler to call GetModels() directly from (1), cutting out the middle person (2), which is fine if GetModels() explicitly required. If, however, (1) it is necessary to respond to any future changes in the called click handler (2), then the above approach should be adopted.
+6
source share

You can use a special event for this. You can put your $.each in an event listener, and then your $.getJSON success handler can trigger this event:

 $('#x').click(function() { var _this = this; $.getJSON(url, data, function(data) { // do things to data... _this.trigger('data-loaded'); }); }); $('#x').on('data-loaded', function() { $.each(...) }); $('#x').click(); 

Demo: http://jsfiddle.net/ambiguous/FeYTB/

+6
source share

Why don't you try

 $('#' + data[0].ID).live('click', function (){ $.each(data[0].ListEntries, function (key, val) { // your stuff here }); }); 

Thus, $.each will be launched only after the start of the click.

0
source share

All Articles