Value won't push to array - javascript

In the code below, I assign a value to a variable from JSON with this var tag = data[j]['text']; and I output it with this console.log(tag); (for testing) which works.
I try to push the values into an array with tags.push(tag); but it WILL NOT WORK!
Why won't these values go into the array? I am just trying to get the contents of tag into an array...
function GetAvailableTags() {
var url = '/TextCodes/TextCodes?key=';
var tagGroups = [];
$('.ui-autocomplete-input').each(function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.getJSON(url + key, function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
});
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
});
}
Thanks for your help.

Because $.getJSON is an asynchronous function. It means that your code
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
will be executed before the $.getJSON callback function :
function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.getJSON(url + key, function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
}
It is why your variable seems to be empty when look into in your code above, but how it is possible that the data are printed with console.log(tag); in the callback function.
Update
Here is an example of using $.ajax method instead of $.getJSON to specify that the data must be retrieved synchronously using the parameter asynch : false
By that way, the server call response (success callback) is mandatory to continue the process. The disadvantage of this non-standard way is that your web page could be freezed waiting the server response. It is not the best elegant way to do that, but sometimes it is useful.
function GetAvailableTags() {
var url = '/TextCodes/TextCodes?key=';
var tagGroups = [];
$('.ui-autocomplete-input').each(function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.ajax({
url: url + key,
type: 'POST',
asynch: false,//specify to stop JS execution waiting the server response
success: function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
},
error : function(jqXHR, textStatus, errorThrown) {
alert('an error occurred!');
}
});
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
});
}

My solution is kind of long and stupid, but it works. Now, I can access the variables like an array textCodes['taxes']. sdespont's async note helped, too.
var textCodes = GenerateTextCodes();
console.log(textCodes);
function GenerateTextCodes() {
var arr = [];
$('.ui-autocomplete-input').each(function () {
var id = $(this).attr('id');
arr[id] = GetAvailableTags(id);
});
//console.log(arr['taxes']);
return arr;
}
// get all autocomplete element IDs and put them into an array
function GetAvailableTags(key) {
var url = '/TextCodes/TextCodes?key=';
var tags = [];
$.ajax({
url: url + key,
type: 'GET',
async: false,
success: function (data) {
//console.log(data[0].text);
//console.log(data.length);
for (var i = 0; i < data.length; i++) {
//console.log(data[i].text);
tags.push(data[i].text);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('an error occurred!');
}
});
//console.log(tags);
return tags;
}

Related

remove duplicate from React project

I'm using React as a front-end library for my rails project, I have been through an issue which is showing the errors for the user, I'm using Ajax to send request but I found my self duplicating error call back function if the server-side returns errors in every request inside every React.Component something like:
$.ajax({
url: URL,
type: METHOD,
data: {
//data
},
success: function () {
//calling some function
}.bind(this),
error(error) {
// begin
server_errors = JSON.parse(error.responseText);
array_of_keys_of_errors = Object.keys(server_errors);
for( i = 0 ; i < array_of_keys_of_errors.length; i++){
nested_keys = Object.keys(server_errors[array_of_keys_of_errors[i]]);
for( j = 0 ; j < nested_keys.length; j++){
array_of_errors = server_errors[array_of_keys_of_errors[i]][nested_keys[j]];
for( k = 0 ; k < array_of_errors.length; k++){
bootbox.alert({
message: nested_keys[j] + ' ' + array_of_errors[k],
closeButton: false,
});
}
}
}
// end
},
});
Is there an efficient way to keep my code away from redundancy, I was thinking about a shared file contains shared functions and include it inside each React.Component but I didn't find something similar to this.
You could create a function to handle your errors:
function handleErrors(errors) {
const server_errors = JSON.parse(error.responseText);
const array_of_keys_of_errors = Object.keys(server_errors);
for( i = 0 ; i < array_of_keys_of_errors.length; i++){
nested_keys = Object.keys(server_errors[array_of_keys_of_errors[i]]);
for( j = 0 ; j < nested_keys.length; j++){
array_of_errors = server_errors[array_of_keys_of_errors[i]][nested_keys[j]];
for( k = 0 ; k < array_of_errors.length; k++){
bootbox.alert({
message: nested_keys[j] + ' ' + array_of_errors[k],
closeButton: false,
});
}
}
}
}
And share that function across your files.
You would use it like this:
$.ajax({
url: URL,
type: METHOD,
data: {
//data
},
success: function () {
//calling some function
}.bind(this),
handleErrors
})

Deferred objects with multiple getJSON calls that depend on each other

I am making 3 get JSON calls in myFunction() that gets called on a button click. 2 of these getJSONs depend on each other for their execution. It basically parses through 10 web pages and collects some data. With this data it will go to another page and collect some other data. I want to display "DONE" at the end of myFunction so the user knows that we have finally got all data and the search operation is complete. However these calls, I think, are asynchronous, so I use deferred objects. But even though I pass all calls to $.when.apply(call1,call2,call3), it displays the "DONE" before any data is printed on the console. Once it prints "DONE", then it starts to print the results. How can I modify my code so that I would be able to display "DONE" only when myFunction has ran completely for all 10 pages and has printed all data on the console.
var call1 = [];
var call2 = [];
var call3 = [];
function myFunction() {
data3 = [];
url = ''; // some URL here
call3.push($.getJSON(url, function(data4) {
data3 = data4;
}));
for (var page = 1; page < 10; page++) {
(function(page) {
url = 'http://example.com/' + page;
call1.push($.getJSON(url, function(data1) {
for (var num = 0; num < data1.standings.results.length; num++) {
(function(num) {
url = 'http://example.com/' + data1.entry[num];
call2.push($.getJSON(url, function(data2) {
for (var i = 0; i < 15; i++) {
(function(i) {
console.log(data3.ele[(data2.p[i].element) - 1].x);
return;
}
})(i);
}
})
);
})(num);
}
})
);
})(page);
};
$.when.apply(call1, call2, call3).then(function() {
console.log("DONE");
});
}
I was finally able to solve this problem. As mentioned in the comments, we need to chain various promises and the function structure should match the structure of the when command. So, in the function as call1 was pushed first, I need to call the when command for call1 and then nest the subsequent commands and so on.
var call1 = [];
var call2 = [];
var call3 = [];
function myFunction() {
data3 = [];
url = ''; // some URL here
call3.push($.getJSON(url, function(data4) {
data3 = data4;
}));
for (var page = 1; page < 10; page++) {
(function(page) {
url = 'http://example.com/' + page;
call1.push($.getJSON(url, function(data1) {
for (var num = 0; num < data1.standings.results.length; num++) {
(function(num) {
url = 'http://example.com/' + data1.entry[num];
call2.push($.getJSON(url, function(data2) {
for (var i = 0; i < 15; i++) {
(function(i) {
console.log(data3.ele[(data2.p[i].element) - 1].x);
return;
}
})(i);
}
})
);
})(num);
}
})
);
})(page);
};
$.when.apply($, call1).then(function(){
$.when.apply($, call2).then(function(){
document.getElementsByName('output')[0].value+="Search Completed"+'\r\n';
});
});
}

making multiple ajax calls within a for loop

I'm a relative newbie to javascript and I'm trying to make multiple ajax calls within a for loop. It loops through the elements of an array using a different url for an ajax call each time it goes through the loop. The problem is that the value of the variable 'test' is always equal to "condition4". I'm used to other languages where the value of 'test' would be "condition1", then "condition2" etc as it goes through the for loop. Here is a simplified version of my code:
var myData = [];
var cnt = 0;
var link;
var myCounter = 0;
var myArray = ["condition1", "condition2", "condition3", "condition4"];
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[myCounter];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
}
function GetJSON(callback) {
$.ajax({
url: link,
type: 'GET',
dataType: 'json',
success: function (results) {
callback(results);
}
});
}
I think you can solve this issue by sending and receiving myCounter value to server
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
$.ajax({
url: link,
type: 'GET',
dataType: 'json',
data: { myCounter: myCounter}
success: function(results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = results.data[i].myCounter
myData[cnt] = {
"id": id,
"test": test
};
cnt++;
}
}
});
}
When you are executing the loop, it attaches the myCounter reference. Then, due to the async task, when it finishes and call 'myCounter', it has already achieved the number 4. So, when it call 'myCounter', it is 4. To isolate the scope, you need to create a new scope every iteration and isolating each value of 'myCounter'
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
//IIFE
(function() {
var ownCounter = myCounter; //Isolating counter
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[ownCounter];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
})();
}
Or...
for (let x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[x];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
}

Parse Queries through Nested For Loops is Giving Duplication of Results

I'm attempting to loop through an array to query my order class to find an associated id, then loop through
another class with that id.
There are 4 elements in the origin array, and they should match to an id each of which have 43 elements in the 3rd query.
However instead of getting 43 results from the 3rd query per id, I'm getting 12*43 results.
I can't figure out how my code is wrong and I've tried containedIn also without any results.
$scope.positionIds = [];
$scope.dataDictionary = {};
$scope.quotes = function () {
for (var i=0; i < $scope.positions.length; i++){
var positionNow = $scope.positions[i];
var orderQuery = new Parse.Query('Order');
orderQuery.equalTo('objectId', positionNow );
orderQuery.find({
success: function(result) {
console.log(result);
for (var j=0; j < result.length; j++){
$scope.positionIds.push(result[j].attributes.positionId);
}
for (var k=0; k < $scope.positionIds.length; k++){
var portfolioQuery = new Parse.Query('DayPosition');
portfolioQuery.limit(1000);
var positionSecond = $scope.positionIds[k];
portfolioQuery.equalTo('positionId', positionSecond);
console.log("positionId", $scope.positionIds[k]);
portfolioQuery.find({
success: function(result) {
console.log("count", result.length);
for (var h=0; h < result.length; h++){
// console.log("count", result.length);
console.log("double inside data time", result[h].createdAt);
console.log("double inside data id", $scope.positionIds[k]);
console.log("value", result[h].attributes.currentValue);
var values = [];
values.push([result[h].createdAt,
result[h].attributes.currentValue]);
if (!$scope.dataDictionary[result[h].attributes.positionId]){
$scope.dataDictionary[result[h].attributes.positionId] = [];
} else {
$scope.dataDictionary[result[h].attributes.positionId].push(values);
}
}
console.log("final data", $scope.dataDictionary);
},
error: function (error) {
console.log("this error", error);
}
});
}
},
error: function (error) {
console.log("this error", error);
}
});
}
};

Refactor two jQuery UI auto-completes to be more Functional & DRY

I have two jQuery UI auto-completes on the same page and I'd like to make the code more "functional" and terse. My background is almost strictly OO and I'd like to get more serious about writing more functional JavaScript.
Both of these functions are properties of an object literal that I'm using to namespace the functions on the page. Right now there is a lot of code that's repeated between the functions and I'd like to use something similar to the "partial application" pattern to reduce the code.
autocomplete 1:
initProject : function(){
var selected = 0;
var suggestions = [];
var projs;
var len;
$("#projectNum").autocomplete({
source : function(req, add){
$.getJSON("projectList.do?method=viewProjectListJSON&contractID=" + req.term, function(data){
//clear the suggestions array
suggestions = [];
projs = data[0];
len = projs.length;
for(var i = 0; i < len; i++){
suggestions.push(projs[i][1]);
};
add(suggestions);
});//end getjson callback
},
minLength : 2,
select : function(){
thisval = $(this).val();
for(var i = 0;i < len; i++){
if(thisval === projs[i][1]){
$("#projectID").val(projs[i][0]);
return;
}
}
}
})
},
autocomplete 2:
initCAU : function(){
var selected = 0;
var suggestions = [];
var caus;
var len;
$("#cauNum").autocomplete({
source : function(req, add){
$.getJSON("cauList.do?method=viewCAUListJSON&cauNumber=" + req.term, function(data){
suggestions = [];
caus = data[0];
len = caus.length;
for(var i = 0; i < len; i++){
suggestions.push(caus[i][1].toString());
};
add(suggestions);
}); //end getjson callback
},
minLength : 2,
select : function(){
thisval = $(this).val();
for(var i = 0;i < len; i++){
if(parseInt(thisval,10) === caus[i][1]){
$("#cauID").val(caus[i][0]);
return;
}
}
}
})
},
//factored-out common code...
var autocompleter = function(urlPrefix, fragment) {
var selected = 0;
var suggestions = [];
var items;
var len;
return ({
minLength: 2,
source: function(req, add) {
$.getJSON(urlPrefix + req.term, function(data) {
suggestions = [];
items = data[0];
len = items.length;
for(var i = 0; i < len; i++) {
suggestions.push(projs[i][1]);
};
add(suggestions);
}); //end JSON callback
}, //end source callback
select: function() {
var thisVal = $(this).val();
for(var i = 0; i < len; i++) {
if(thisVal === items[i][1]) {
$(fragment).val(items[i][0]);
return;
}
}
} //end select callback
});
};
//verbose but clear way to achieve what you were doing before.
var initCAU = function() {
var attachTo = "#cauNum";
var urlPrefix = "cauList.do?method=viewCAUListJSON&cauNumber=";
var fragment = "#cauID";
$(attachTo).autocomplete(autocompleter(urlPrefix, fragment));
};
var initProject = function() {
var attachTo = "#projectNum";
var urlPrefix = "projectList.do?method=viewProjectListJSON&contractID=";
var fragment = "#projectID";
$(attachTo).autocomplete(autocompleter(urlPrefix, fragment));
};

Categories

Resources