How do I loop a variable in the Javascript function call? - javascript

I have the following loop for a series of similar click events in jQuery. Everything works fine except for the last line below with the comment. How can I make each loop iteration call these functions respectively: step1(), step2(), step3(), etc.?
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
step + i(); // I'm stuck here. This doesn't work to create the function calls step1(), step2(), etc.
});
}

Assuming your functions are defined in the global context:
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
window["step" + i]();
});
}

make an array of the step functions.
var step = [
function () { /* step 0 */ },
function () { /* step 1 */ },
function () { /* step 2 */ }
// ...
];
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
step[i]();
});
}

Related

onclick in div not calling function

I have a problem where onclick in the code does not work, as the function does not run when clicking.
function kaka(x) {
$('.' + x).each(function() {
html += this.outerHTML;
});
$("#klasa").html(html);
alert(html);
}
tab = ciong.split("&");
dlu = tab.length;
tab = removeDuplicates(tab);
for (var i = 0; i <= dlu; i++) {
$("#linki").html($("#linki").html() + "<div onclick='kaka(\'" + tab[i] + "\');'> " + tab[i] + " </div>");
}

Second loop is not working

I´m running this test with nightwatch and I have a loop inside a loop, first one runs ok but it fails going inside 2nd loop.
I wrote a console.log and returns:
Number of links:[object Object]
This is my code:
What´s the reason for not entering in loop 2?
Thanks in advance.
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li').length
},
function(result) {
total_links = result.value;
console.log("Number of main links:" + total_links);
for (var i = 2; i <= total_links; i++) {
(function (i) {
browser.waitForElementPresent('.menuElementsAgregator', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>a')
.waitForElementVisible('.menuElementsAgregator>li:nth-child(' + i + ')', 2000)
.execute(
function () {
return document.querySelectorAll('.menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level .has-sub .clickableTabWithLink').length
},
function(result) {
total_links2 = result.value;
console.log("Number of links:" + total_links2);
for (var j = 2; j <= total_links2 + 1; j++) {
browser.waitUntilElementIsClickable('.menuElementsAgregator>li:nth-child(' + i + ')')
.click('.menuElementsAgregator>li:nth-child(' + i + ')')
.waitForElementPresent('.menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level>li:nth-of-type(' + j + ').has-sub', 5000)
.click(' .menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level>li:nth-of-type(' + j + ').has-sub .clickableTabWithLink:first-child')
.pause(1000)
.waitForElementVisible('.games-list', 5000);
}
}
)
})(i);
}
})
The problem is that total_links is not an integer but an object.
Try to replace
console.log("Number of main links:"+ total_links);
with
console.log("Number of main links:", total_links);
That will show you what's inside total_links. If you can't fix it add a comment with the content of total_links
Absolutely this code would not work, because you cant use a callback in a loop like that,your index 'i' in second loop would be equal 'total_links.length' all the time. You can try this:
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li').length
},
function(result) {
total_links = result.value;
console.log("Number of main links:" + total_links);
for (var i = 2; i <= total_links; i++) {
(function(i){ // this is a closure
browser.waitForElementPresent('.menuElementsAgregator', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>a')
.waitForElementVisible('.menuElementsAgregator>li:nth-child(' + i + ')', 2000)
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub').length
},
function(result2) {
total_links2 = result2.value;
console.log("Number of links:" + total_links2);
for (var j = 0; j <= total_links2; j++) {// i = total_link.length already, before get in to this loop.
browser.waitForElementPresent('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub:nth(' + j + ')', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub:nth(' + j + ')>a')
.pause(3000)
.waitForElementVisible('.games-list', 5000);
}
}
)
})(i) // close
}
}
)
You should take a look at api .perform() , this will be help a a lot for this kind of work. It made my code cleaner and readable.
Ps: Spend some time to research closure.

Arrays returning undefined for API calls (spotify app)

Hey guys I'm working on a Javascript web app which uses Spotify API. I'm trying to return the top 5 albums of a given artist in a table. So far I got the API calls working and they return a table which displays ALL the albums of an artist in no particular order. I'm trying to shrink the table to the top 5 albums based on "popularity" which is the fifth column of the table.
var popsort = new Array(new Array());
var count = 0;
$(document).ready(function () {
$("#searchbutton").click(function () {
search();
});
,
function search() {
var query1 = document.getElementById('querybox').value;
$.get("https://api.spotify.com/v1/search?q=" + query1 + "&type=artist", function (data) {
//alert(data.artists.items[0].id);
getSeveralAlbums(data.artists.items[0].id);
});
}
function getSeveralAlbums(artistid) {
//alert(artistid);
$.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
function (json) {
//bob = json;
//console.log(json);
console.log(json.items.length);
for (var i = 0; i < json.items.length; i++) {
createArray(json.items[i].href);
}
//console.log(count);
popsort.sort(sortPopularity);
//getAlbumInfo(json.items[i].href);
getAlbumInfo(popsort);
});
}
function getAlbumInfo(popsort) {
var tr;
console.log(popsort);
// i<json.length
// Sort the array first by popularity. And then create a for loop and print the first five.
tr = $('<tr/>');
for (var i = 0; i < 5; i++) {
tr.append("<td>" + popsort[i][0] + "</td>"); // Album Name
tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
tr.append("<td>" + popsort[i][4] + "</td>"); // Popularity
}
$('table').append(tr);
}
function createArray(albumhref) {
//console.log(albumhref);
$.getJSON(albumhref,
function (json) {
// i<json.length
// Sort the array first by popularity. And then create a for loop and print the first five.
console.log(count);
popsort[count][0].push(json.name);
popsort[count][1].push(json.artists[0].name);
popsort[count][2].push(json.release_date);
popsort[count][3].push(json.tracks.total);
popsort[count][4].push(json.popularity);
++count;
//alert("table compiled");
//alert("Table done");
});
}
function sortPopularity(a, b) {
if (a[4] === b[4]) {
return 0;
}
else {
return (a[4] < b[4]) ? -1 : 1;
}
}
});
I use the click function at the top to get the artist name from a textbox, pass that into the "search" function which returns an artistid. I pass this artistid into the "getSeveralAlbums" functions. The json call in this function returns the hrefs to all the albums of a specific artist which I want to store in an 2D array along with the popularity. My "sortPopularity" function near the bottom will ideally sort this array by the fifth element which is "popularity" and then I plan to pass this sorted array (popsort) into the getAlbumInfo function which has a for loop printing 5 times, which will ideally print the first five elements of the popsort array. After sorting this will ideally be the top 5 most popular albums of an artist.
When I try to run this program, it returns an error undefined for both popsort[count][0].push(json.name); in the createArray function, and it returns an error undefined for tr.append("<td>" + popsort[i][0] + "</td>"); in the getAlbumInfo function. What am I doing wrong?
Update: (new code)
var popsort = new Array(new Array());
var count = 0;
var looopCount = 0;
$(document).ready(function () {
$("#searchbutton").click(function () {
search();
});
function search() {
var query1 = document.getElementById('querybox').value;
$.get("https://api.spotify.com/v1/search?q=" + query1 + "&type=artist", function (data) {
getSeveralAlbums(data.artists.items[0].id);
});
}
function getSeveralAlbums(artistid) {
$.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
function (json) {
console.log(json.items.length);
looopCount = json.items.length;
for (var i = 0; i < json.items.length; i++) {
createArray(json.items[i].href);
}
});
}
function getAlbumInfo(popsort) {
var tr;
// Sort the array first by popularity. And then create a for loop and print the first five.
tr = $('<tr/>');
for (var i = 0; i < 5; i++) {
tr.append("<td>" + popsort[i][0] + "</td>"); // Album Name
tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
tr.append("<td>" + popsort[i][4] + "</td>"); // Popularity
}
$('table').append(tr);
}
function createArray(albumhref) {
$.getJSON(albumhref,
function (json) {
if (popsort.length <= count) {
popsort.push(new Array());
}
// Sort the array first by popularity. And then create a for loop and print the first five.
popsort[count].push(json.name);
popsort[count].push(json.artists[0].name);
popsort[count].push(json.release_date);
popsort[count].push(json.tracks.total);
popsort[count].push(json.popularity);
++count;
batchSort(--looopCount);
});
}
function sortPopularity(a, b) {
if (a[4] === b[4]) {
return 0;
}
else {
return (a[4] > b[4]) ? -1 : 1;
}
}
function batchSort(i) {
if (i <= 0) {
popsort.sort(sortPopularity);
getAlbumInfo(popsort);
}
}
});
First is that you are accessing undefined key of popsort in createArray(), use .push() instead. Second, the getAlbumInfo(sortPopularity); function is already called while the first $.getJSON(albumhref, fn...); reponse has not yet returned thus leaving you with an empty array to access. Tht is why you get an undefined return when accessing the popsort
What I would do is I will create a descending counter and add it to the createArray's $.getJSON() callback, like this:
var popsort = new Array(new Array());
var count = 0;
var looopCount = 0;
function getSeveralAlbums(artistid) {
$.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
function (json) {
console.log(json.items.length);
looopCount = json.items.length
for (var i = 0; i < json.items.length; i++) {
createArray(json.items[i].href);
}
// call both popsort.sort(sortPopularity); and getAlbumInfo(popsort); after all the data is loaded to popsort, not here.
});
}
function createArray(albumhref) {
$.getJSON(albumhref,
function (json) {
if (popsort.length <= count) {
// if the length of popsort is less than count, it means that that index(count) is not yet present in popsort
// push to add an item with index=count to popsort
popsort.push(new Array());
}
popsort[count].push(json.name);
popsort[count].push(json.artists[0].name);
popsort[count].push(json.release_date);
popsort[count].push(json.tracks.total);
popsort[count].push(json.popularity);
++count;
batchSort(--looopCount);
});
}
function batchSort(i) {
if (i <= 0) {
popsort.sort(sortPopularity);
getAlbumInfo(popsort);
}
}
});
function getAlbumInfo(popsort) {
for (var i = 0; i < 5; i++) {
tr.append("<tr><td>" + popsort[i][0] + "</td>"); // Album Name
tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
tr.append("<td>" + popsort[i][4] + "</td></tr>"); // Popularity
}
}
Haven't tested it though, but that's the thought.. Hope it helped.

Javascript Closure inside loops

window.config = {
"Environments": [
"LH5",
"LH8",
"AMS"
],
"Clusters": [
4,
4,
4
]
};
Below is the promise object:
for (var i = 0; i < window.config.Environments.length; i++) {
for (var j = 1; j < window.config.Clusters[i] + 1; j++) {
promiseObj.physical[window.config.Environments[i] + "#Cluster" + j] = $http.get('http://url0/search?idc=' + window.config.Environments[i] + '&type=Physical&cluster=' + j).success(function(data) {
$scope.servers = data; // get data from json
countcores[window.config.Environments[i] + "#Cluster" + j] = 0;
countmemory[window.config.Environments[i] + "#Cluster" + j] = 0;
angular.forEach($scope.servers, function(item) {
countcores[window.config.Environments[i] + "#Cluster" + j] = parseInt(countcores[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.cores);
countmemory[window.config.Environments[i] + "#Cluster" + j] = parseInt(countmemory[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.memory);
});
});
promiseObj.virtual[window.config.Environments[i] + "#Cluster" + j] = $http.get('http://url/search?idc=' + window.config.Environments[i] + '&type=Virtual&cluster=' + j).success(function(data) {
$scope.servers = data; // get data from json
countvirtualcores[window.config.Environments[i] + "#Cluster" + j] = 0;
countvirtualmemory[window.config.Environments[i] + "#Cluster" + j] = 0;
angular.forEach($scope.servers, function(item) {
countvirtualcores[window.config.Environments[i] + "#Cluster" + j] = parseInt(countvirtualcores[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.cores);
countvirtualmemory[window.config.Environments[i] + "#Cluster" + j] = parseInt(countvirtualmemory[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.memory);
});
});
}
}
What appears to be happenning is that the loop is going quicker than the promise object and j is reaching 5 before the promise object and what is logged is
["undefined#Cluster5"] = 1280
What I'm expecting is
["LH5#Cluster1"] = somevalue;
["LH5#Cluster2"] = somevalue;
["LH5#Cluster3"] = somevalue;
["LH5#Cluster4"] = somevalue;
["LH8#Cluster1"] = somevalue;
["LH8#Cluster2"] = somevalue;
["LH8#Cluster3"] = somevalue;
["LH8#Cluster4"] = somevalue;
["AMS#Cluster1"] = somevalue;
["AMS#Cluster2"] = somevalue;
["AMS#Cluster3"] = somevalue;
["AMS#Cluster4"] = somevalue;
I have multiple promiseObjectives running in the same loop(s) - how does this work? I am aware of JavaScript closure inside loops – simple practical example - However this does not help me, I require further assistance.
The referenced URL was made to exemplify what you need to do and in a simple manner. The issue you are encountering is the same issue as the one referenced in the URL. You need to ensure that you are scoping your i & j variables for each function call. Therefore, you need closures around your success function that pass in the i & j variables to return the function that you wish to call when the success() is called for the $http.get() function.
I am not going to do the exact code but it would look somewhat similar to this:
$http.get('http://url').success(function(i,j){
return function (data){
//code stuff happens here
}
}(i,j));
This way the function(i,j){ ... }(i,j) is called and it then returns the actual function return function(data){} with the i & j variables properly scoped and having the values that they did when the function function(i,j){ ... }(i,j) was called.
**As a side note I would change the scoped varaible names from i & j to something more descriptive and less confusing

how to build a dynamic menu using jquery?

I try to create a dynamic menu using jquery:
function createMenu(array) {
var main = $("#mainUl");
for (var i = 0; i < array.length; i++) {
main.append("<li>");
$('li').append("<a href='#" + myArray[i].id + "'><span>" + myArray[i].id + "</span></a>");
main.append("</li>");
}
}
The menu is created, but in each li i get more than one span, there is an "inside" loop (I think...)
createing more spans than needed... how can i solve/control it so each li gets
one span according to the for - loop index ?
You are seeing that behaviour because you are appending that anchor with span in selecting all the li elements.
Try,
function createMenu(array) {
var main = $("#mainUl");
for (var i = 0; i < array.length; i++) {
var xLi =("<li>").appendTo(main);
xLi.append("<a href='#" + myArray[i].id + "'><span>" + myArray[i].id + "</span></a>");
main.append(xLi);
}
}
you can do it simply as below
function createMenu(array) {
var main = $("#mainUl");
for (var i = 0; i < array.length; i++) {
main.append($("<li>").append("<a href='#" + myArray[i].id + "'><span>" + myArray[i].id + "</span></a>"));
}
}
$('li') this selector will get every li on the html so every time you iterate to create a new li element you gonna add a new span to all of them.
Try like this:
function createMenu(array) {
var main = $("#mainUl");
for (var i = 0; i < array.length; i++) {
var menuLine = $('<li>');
menuLine.html("<a href='#" + myArray[i].id + "'><span>" + myArray[i].id + " </span></a>" );
main.append(menuLine);
}
}

Categories