jQuery: insert html with javascript, waiting for it to run - javascript

I'm using $.ajax method to pull some html code and insert it into a 'div.listbox' element, using $('div.listbox').html() method.
I'm aware that .html will insert all HTML code, and execute all javascript code found under the HTML code.
What is actually happening:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
$('div.listbox').html(data.body)}
})
This data.body has a javascript that will make a call to an asynchronous function that will update an element inside the HTML under data.body.
Putting a .live function on the 'div.listbox' element, in order to listen to DOMNodeInserted event, I could see that the javascript method executed by the $...html(data.body) call updated 'div.listbox' element 6 times.
As this number could change, I can't just treat this as my solution, waiting to the element to change 6 times and then do what I want.
So I'm asking if it's possible to wait untill all javascript inside that .html call is executed before continuing to other javascript methods after the $.ajax call.

The only way would be to use a callback function inside your ajax-generated javascript, so you'd have:
//(ajax generated code)
<script>
...
$('div.listbox').css("color", "blue"); //For example, let's assume this code executes asynchronously
div_changed(); //This is the callback function
</script>
Then, in your main script you should have:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
$('div.listbox').html(data.body)
}
})
function div_changed(){
//Here put the code you want to be executed after changes are made
}
This is the only way, note that this is asynchronous.
Hope this helps. Cheers

JavaScript is a functional programming language meaning that you almost everywhere work with functions and can also pass functions as parameters. Let's describe your scenario: In scope A (parent element) you want to do something, but just when in scope B (child element) something happens and finishes. Only scope A knows what it wants to do, and only scope B knows when it finishes its job. So what do you do? Here are some solutions:
Hardcoding your logic of scope A in scope B (spaghetti code)
Get the function back from scope B and execute it in scope A (bad idea)
Pass the logic of scope A as a function to the scope B and let B be the agent to decide when to execute that.
The best method is the third item and this is the spirit of functional programming.

Solve by adding a listener to DOMSubtreeModified event, by doing:
$.ajax({
async: false,
url: 'ReturnSomeDataAsJSON',
data: {some_needed_data},
dataType: 'json',
success: function(data){
external_data = $(data.body)
var data_html = $(data.body)[0]
var data_script = $(data.body)[1].text
listbox_container = $('form#main_form div.listbox-container:nth(0)')
//fill body
listbox_container.html(data_html);
// attach listener
listbox_container.live('DOMSubtreeModified', check_listbox)
// eval script
eval(data_script)
// this script will (some time, asynchonously) update listbox_container
// by adding some data, that I need to deal with
}
})
function check_listbox() {
listbox_internal_ container = $('form#main_form div.listbox-container:nth(1)')
if (listbox_internal_container.length >= 1) {
// do what I want (deal with new data filled),
// because internal container (that will be created
// by the $.ajax call) now exists with some data filled by the
// eval(...) of the script
};
}

Related

Request help understanding Ajax scope when using 'this' in reference to a JS class that the Ajax code is contained in

I have a django web project where the client invokes server-side python code to send data to a third-party service and receive a response using ajax. I have all the client side functionality bundled into a class because there are variables I need the ajax callback function to be able to access. I was hoping a class would help this scoping issue I seem to be having, but the function being called by my ajax code upon success has no idea what context it's in.
My server response contains a list of words I want to render to the screen. I have a wrapper class containing an unordered list object that I've made an instance of in my main class that contains my function that contains my ajax code and another function that the ajax calls upon success. In the success function in the class, I'm using this to refer to my list object I have defined in my main class. The function invoking the ajax says my list is defined, but the function being called by the ajax says it's undefined.
function MainClass(...){
/* Variable I'm trying to access from my ajax callback. */
this.wordlist = new UnorderedList();
this.onAjaxRequest(data){
console.log(this.wordlist); /* defined */
$.ajax({
type: "POST",
url: url,
data: {
csrfmiddlewaretoken: csrfToken,
data: data
},
success: this.onAjaxSuccess
});
}
this.onAjaxSuccess(words){
this.wordlist.updateList(words); /* undefined */
}
}
I have discovered through other posters that doing this: success: this.onAjaxSuccess(this) seems to work (it feels like type casting to me). My this.wordlist reference in onAjaxSuccess is now defined, but the parameter being passed in is no longer my server response, but now a reference of my MainClass. I understand it is literally passing the entire object because of (this), but how do I get my server response data doing that?
You can bind this function context to onAjaxSuccess in the function declaration itself.
function MainClass(){
/* Variable I'm trying to access from my ajax callback. */
this.wordlist = ['hi','buddy'];
this.onAjaxRequest = function(data){
console.log(this.wordlist, 'onAjaxRequest'); /* defined */
$.ajax({
type: "POST",
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
csrfmiddlewaretoken: null,
data: data
},
success: this.onAjaxSuccess
});
}
this.onAjaxSuccess = (function(words){
console.log(this.wordlist, 'onAjaxSuccess'); /* defined */
}).bind(this);
}
var mainClass = new MainClass();
mainClass.onAjaxRequest();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You need to bind the function reference to the object, so that this will work correctly within it. Use:
success: this.ajaxSuccess.bind(this)
Or you can use an arrow function:
success: words => this.ajaxSuccess(this)

Multiple ajax calls in jquery

I am using jquery for my project.
I have the following requirements:
I need to make a function call which invokes 5 other functions.
These 5 functions are ajax calls which work independent of each other. The ajax calls get data from server and appends values to a global object.
I am facing difficulty in finding whether all the ajax calls are done or not. After all the calls are done , I have to set it to localStorage and then load another html file.
What is the best way to do it?
If the number of ajax calls made are constant,You can use the following logic
COUNTER=5;
function reduceCounter(){
COUNTER --;
if(COUNTER == 0)
{
localStorage.Obj=JSON.stringify(Obj);
location.href="nextPage.html";
}
In each of your ajax calls , call reduceCounter() at .always();
eg:
$.ajax({
url: ..
type: 'GET',
dataType: 'json',
})
.done(){...
//set Obj
},
.fail(){...
},.always(){
reduceCounter();
}
mmm... Is it something you can do with jQuery Load, it makes sure everything loaded before you call any function or anything:
$(document).ready(function() {
//Make sure all DOMs loaded!
}):

Returning the Result of a $.getJSON-Function

I need to load a php-script with ajax, which creates a JSON-result.
An example of the getEvent.php is:
[{"id":"1","start":"Wed Jul 18 12:00:00 GMT+0200 2012","end":"Wed Jul 18 13:30:00 GMT+0200 2012","title":"leer"}]
In order to transmit this result to another function, I have to be able to assign it to an variable. I tried it many ways, but it has never worked out.
function loadEvents(){
var cdata;
$.getJSON({
type: 'GET',
url: 'getEvent.php',
asynch:false,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(jsonData) {
cdata = jsonData;
},
error: function() {
alert('');
}
});
return cdata;
}
cdata = jsonData; doesnt seem to work
I have only found ways to asign parts of the result (jsonData) to a variable, but it seems that the entire jsonData can't be returned.
Can anybody help me with my problem? I have to return the complete jsonData to another function...
Thanks
getJSON is an asynchronous function (expectiong just a url, no settings object (Docu)), meaning that it will return a result as soon as the answer from the server is done. In the meantime your function continues execution. Thus, at the moment you return cdata, your success function hasn't executed yet. You need to either use a callback or set the function to be synchronous (which you are trying to do but have a typo in there - it's async without h - also if you want to pass additional settings, you can't use getJSON() but have to use $.ajax().
instead of making the call synchronous, using the callback is probably the better solution:
instead of
success: function(jsonData) {
cdata = jsonData;
},
write:
success: function(jsonData) {
workWithResult(jsonData);
},
// this is called the "callback" function, it is executed when the ajax-request
// returned successfully
function workWithResult(data){
// now you can work with the data, which is guaranteed to exist
}
First thing, why are you using getJSON?
$.ajax seems to suit more to your requirement.
Second,
The moment you return the cdata comes before the server responds. Your success handler will be executed once the server responds. In the current case, you won't be getting the data you are looking for. :)
What you can do to get around with this is to make the variable cdata global.
And just assign the value to cdata in success handler (which you have done already)
PS : Making variables global is not a good programming practice. (Or at least I don't recommend making use of global variables)
Post your specific requirement, like in what way you are going to use the returned value. So that we can see how we can avoid that global beast.
for eg:
success: function(result){
yourTargetFunction(result); // call the target function with returned data as a paramenter to it
}

consolidating $.ajax

I have several ajax call on my page and I want to consolidate them into one function.
For now I have this type of function in several places:
function AjaxCallOne () {
//do something
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: TheURL,
data: "{'TheData':'" + JsonData + "'}",
dataType: "json",
cache: "false",
success:...
error:...
});
}
I want to write a single function that'll be used for all ajax calls like this:
function MyGeneralAjaxCall(TheData, TheURL, TheSuccessFunction, TheErrorFunction) {
$.ajax({ .... });
}
My question is this: if I do that and the user send two ajax calls, almost simultaneously, to the point where the second ajax call is made before the returning data of the first call comes back, will the success or error functions trigger for the the correct call. I'm worried that the success function that'll be executed won't be for the proper ajax call if the user triggers a second call before the first one is returned.
Thanks.
Your approach will work as you expect. Each success function, etc., that you pass in will be used individually by each associated AJAX call. (All of your parameters will be kept together.)
First, There's no single, global set of callbacks for ajax requests. Each ajax invocation gets it's own set of callbacks.
Secondly: $.ajax({...}) is your MyGeneralAjaxCall... if you are thinking you need a set of default options, a better way would be to set up a
var defaultoptions = { type: "POST", ...} //put default options, mimetypes, etc, here
(or something that returns that) and then wherever needed do:
var myajaxoptions = $.extend({},defaultoptions,myoverrides);
$.ajax(myajaxoptions);
That's much more extensible. No need to make up "men in the middle". Your approach will work, but I could easily see more than one MyGeneralAjaxCall being created. If you can manage not creating 5 or more methods like that MyGeneralAjaxCall, I suppose you'll be doing ok, but it could get nasty real quick.

jQuery Async Issue, Variable Assignment After GET Request

I'm sure the solution is staring me right in the eyes, but I just cannot see it. I am trying to load an object from an outside file source. I've tried it several which ways using jQuery's built in methods, but keep returning undefined. Is my issue the scope? I need partnerData right where it is because of other dependent methods in my script. I don't want to operate the rest of my site's functions from within the $.get callback. Any help is greatly appreciated, here's the code:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
});
console.log(partnerData); /* returns undefined instead of object */
});
EDIT:
Thanks for all the feedback everyone. This is the solution I went with:
var partnerData;
$.ajax({
url: 'data/partners.json',
dataType: 'json',
async: false,
success: function(data) {
partnerData = data;
}
});
The reason why you're seeing undefined is because ajax requests are asynchronous by default. This means your get method gets invoked and the code flow moves down to the next statement while the request executes in the background. Your callback function is later invoked when the request completes.
Using callback functions is a common pattern used in situations like this. But you seem to be saying you don't want to do or can't do that. In that case, you could use async: false which would force the request to be synchronous. Keep in mind however, that your code will be blocked on the request and if it's a long-lived request, the user experience will degrade as the browser will lock up.
P.S. You shouldn't need to parseJSON - if response has the correct mime-type set, jQuery will intelligently guess the type and parse the JSON automatically. And in case the server isn't sending back the correct mime-type, you can also explicitly tell jQuery what the expected return data type is; see the dataType argument to $.get() .
One way you might modify your code, to force synchronous requests:
$.ajax({
type: 'GET',
url: 'data/partners.json',
success: function(file){
partnerData = $.parseJSON(file);
//ideally you would perform a callback here
//and keep your requests asynchronous
},
dataType: 'json',
async: false
});
function is proccessed to the end event when ajax is still being proccessed. insert it into callback function
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
console.log(partnerData);
});
});
I would say that your problem is the same of the one that I just solved, if $.get is AJAX! and it is setting a variable, to read that variable outside the callback you need to wait the response! So you have to set async=false!
console.log in synchronous and get is async.
try:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
test();
});
function test(){
console.log(partnerData);
}
});

Categories