I'm trying to iterate over an array and assign a variable with a for loop. So something like this:
function Person(name, status){
this.name = name;
this.status = status;
}
var status = [];
var array = ["bill","bob","carl","ton"];
function exAjax(function(){
for(var i = 0; i < array.length; i++){
var name = array[i];
console.log(name); =====> this gives the correct name
$.ajax({
url: xxxxxxx,
success: function(data){
if(data.stream === null){
var person = new Person(name, "dead");
console.log(name); =====> return undefined until the last
person
status.push(person);
}
}
})
name = "";
}
})
The problem I'm having is that name is not getting into the success function. I thought js keeps traveling upwards to look for the variable if it doesn't exist in it's current scope? I'm getting undefined for the name variable if I try to console.log name! Scope masters what am I doing wrong?
You can use .queue()
, $.map()
to maintain scope of name
. Also, change status
array to an object having property status
where value is an array to prevent possible conflict with this.status
of Person
object.
Note, you can also chain .promise(/* queueName */)
to perform tasks at .then()
when all queued functions in queueName
, i.e.g., "status"
have been called, queueName
.length
is 0
.
function Person(name, status){
this.name = name;
this.status = status;
}
var blob = new Blob(['{"stream":null}'], {type:"application/json"});
var url = URL.createObjectURL(blob);
// change `status` array reference, e.g., to `arr`
var arr = {status:[]};
var array = ["bill","bob","carl","ton"];
$(arr).queue("status", $.map(array, function(curr) {
return function(next) {
var name = curr;
// do asynchronous stuff
$.ajax({url:url, dataType:"json"})
.then(function(data) {
if(data.stream == null){
var person = new Person(name, "dead");
console.log(name, person);
arr.status.push(person);
}
})
.then(next) // call next function in `"status"` queue
}
}))
.dequeue("status")
.promise("status")
// do stuff when all functions in `"status"` queue have completed,
// `"status"` queue `.length` is `0`
.then(function() {
// `this` : `arr` as jQuery object
// `this[0].status`: array containing objects pushed to `arr.status`
console.log(this[0].status); // $(this).prop("status");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
jsfiddle https://jsfiddle.net/nnayjckc/2/
You can alternatively use $.when()
, .apply()
, $.map()
, to return same result
function Person(name, status) {
this.name = name;
this.status = status;
}
var blob = new Blob(['{"stream":null}'], {
type: "application/json"
});
var url = URL.createObjectURL(blob);
// change `status` array reference, e.g., to `arr`
var arr = {
status: []
};
var array = ["bill", "bob", "carl", "ton"];
$.when.apply($, $.map(array, function(curr) {
var name = curr;
return $.ajax({
url: url,
dataType: "json"
})
.then(function(data) {
if (data.stream == null) {
var person = new Person(name, "dead");
console.log(name, person);
arr.status.push(person);
}
})
}))
.then(function() {
console.log(arr.status)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
jsfiddle https://jsfiddle.net/nnayjckc/3/
That's because $.ajax
perform an asynchronous HTTP (Ajax) request. It means that your for
loop won't wait for success
to complete. Instead it will continue with its iteration.
One way (of the many possible solutions), is to make this $.ajax
synchronous
with the async: false
option
From the documentation
async (default: true)
Type: Boolean
By default, all requests are
sent asynchronously (i.e. this is set to true by default). If you need
synchronous requests, set this option to false.
for(var i = 0; i < array.length; i++){
var name = array[i];
console.log(name); =====> this gives the correct name
$.ajax({
url: xxxxxxx,
async: false,
success: function(data){
if(data.stream === null){
var person = new Person(name, "dead");
console.log(name); =====> return undefined until the last
person
status.push(person);
}
}
})
name = "";
}
})