Reputation: 401
i have an ajax call and it works good , when i call a new ajax call inside the old one , i got error in the first call
$.getJSON("http://localhost/Mar7ba/Ontology/getRelatedConceptsAndRelations/"+conceptName+"/TRUE",function(data){
var concepts = data[0];
var relations = data[1];
for(var i = 0 ; i < concepts.length ; i++){
var IOS = '';
$("#ioAddRelatedConcepts").append('<p>\n\
connect to\n\
<span class="ioAddConcept">'+concepts[i]+'</span>\n\
with\n\
<span class="ioAddRelation">'+relations[i]+'</span>\n\
<select name ="concetedIOs[]" class="TypeSelector">\n\
'+IOS+'</select>\n\
<span class="errorMessage"></span>\n\
<a href="#" class="removeA" id="aioRemoveIO">remove</a>\n\
</p>\n\
<p>');
}
});
$.getJSON("http://localhost/Mar7ba/Ontology/getRelatedConceptsAndRelations/"+conceptName+"/TRUE",function(data){
var concepts = data[0];
var relations = data[1];
for(var i = 0 ; i < concepts.length ; i++){
$.getJSON("http://localhost/Mar7ba/InformationObject/getIOsForConcept/"+concepts[i]+"/TRUE",function(data1){
var IOS = '';
$("#ioAddRelatedConcepts").append('<p>\n\
connect to\n\
<span class="ioAddConcept">'+concepts[i]+'</span>\n\
with\n\
<span class="ioAddRelation">'+relations[i]+'</span>\n\
<select name ="concetedIOs[]" class="TypeSelector">\n\
'+IOS+'</select>\n\
<span class="errorMessage"></span>\n\
<a href="#" class="removeA" id="aioRemoveIO">remove</a>\n\
</p>\n\
<p>');
});
}
});
after that , the concepts[i] and the relations[i] will be as undifined and the data1.length always null and the this is the second php code for ajax
public function getIOsForConcept($conceptName, $AJAX) {
if ($AJAX) {
$results = $this->model->getIOsForConcept($conceptName);
$IOs = array();
$i = 0;
while ($row = $results->fetch()) {
$IOs[$i] = $row['name'];
$i++;
}
return json_encode($IOs);
}
}
and i tried it and it works good
Upvotes: 0
Views: 396
Reputation: 339776
You can't use a loop variable ( i
in your case) inside a callback function - it'll have whatever value it had when the loop terminated by the time your async callback function is invoked.
As you're already using jQuery, you might as well use $.each()
:
$.getJSON(..., function(data) {
var concepts = data[0];
var relations = data[1];
$.each(concepts, function(i, value) {
// concepts[i] is OK to use now, and is also in "value"
// relations[i] is OK to use too
$.getJSON(..., function() {
// you can still use them here, too!
});
});
});
which will ensure that i
is correctly bound to the current iteration number each time.
Upvotes: 4
Reputation: 150010
The reason that concepts[i]
and the relations[i]
are undefined within the callback function of the inner $.getJSON()
function is that $.getJSON()
is aysnchronous which means that the entire for loop will have finished running before any of the callbacks occur on the inner $.getJSON()
calls - so by the time these inner callbacks occur i
is one higher than the maximum index of the concepts
and relations
arrays.
To get around this you can introduce an extra closure to keep the values from each iteration:
$.getJSON("http://localhost/Mar7ba/Ontology/getRelatedConceptsAndRelations/"+conceptName+"/TRUE", function(data){
var concepts = data[0];
var relations = data[1];
for(var i = 0 ; i < concepts.length ; i++){
(function(currentConcept, currentRelation) {
$.getJSON("http://localhost/Mar7ba/InformationObject/getIOsForConcept/"+currentConcept+"/TRUE" , function(data1){
var IOS = '';
$("#ioAddRelatedConcepts").append('<p>\n\
connect to\n\
<span class="ioAddConcept">'+ currentConcept +'</span>\n\
with\n\
<span class="ioAddRelation">'+ currentRelation +'</span>\n\
<select name ="concetedIOs[]" class="TypeSelector">\n\
'+IOS+'</select>\n\
<span class="errorMessage"></span>\n\
<a href="#" class="removeA" id="aioRemoveIO">remove</a>\n\
</p>\n\
<p>');
});
})(concepts[i], relations[i]);
}
});
The anonymous function I've added inside the for loop will run once per iteration creating separate closures each with their own currentConcept
and currentRelation
.
EDIT: To make it really obvious what I've changed compared to your original code--
Add the following line as the first thing inside your existing for
loop:
(function(currentConcept, currentRelation) {
And then the following line as the last thing before your existing for
loop's closing }
:
})(concepts[i], relations[i]);
And then everywhere inside the for
loop where you did have concepts[i]
and relations[i]
change them to currentConcept
and currentRelation
.
Upvotes: 3