Pushing Elements into an Array That Is Inside a Callback Function - javascript

So I'm using nightwatch for this and can't seem to push elements to an array that is inside a callback. It's showing "undefined".
var tab = [];
exports.command = function (control,tabs)
{
var self=this;
var split = tabs.split("~"); //DELIMIT "tabs" PARAMETER
self.elements('css selector', control+" :first-child", function (result) //COUNT THE CHILD OF PARENT
{
var x = result.value;
var screenTabLen = x.length; //GET THE LENGTH OF ACTUAL TABS IN THE SCREEN
var tabLen = split.length; //GET THE LENGTH OF DELIMITED "tabs"
function getTabText(index)
{
self.getText(control + " > :nth-child(" + index + ")", function(result){
tab.push(result.value);
});
}
for (i=1; i<screenTabLen; i++)
{
getTabText(i);
}
console.log("TAB >> " + tab[1]);
});
};
how do I resolve this? thanks in advance!
EDIT: Pasting the whole code

You just made a typo :) you are trying to push to tab. But the array you defined is called bat.
var bat = []; //global variable
//here is your array called bat.
function getTabText(index)
{
self.getText(control + " > :nth-child(" + index + ")", function(result){
bat.push(result.value); //push values to array
//change the tab to bat and you are good.
});
}
for (i=1; i<screenTabLen; i++)
{
getTabText(i); //loop function
}
console.log("TAB === " + bat[1]); //getting undefined here

Change tab.push() to bat.push() or change all bat to tab
var bat = []; // global variable
function getTabText(index) {
self.getText(control + " > :nth-child(" + index + ")", function(result) {
bat.push(result.value); // push values to array
});
}
for (i=1; i<screenTabLen; i++) {
getTabText(i); // loop function
}
console.log("TAB === " + bat[1]); // getting undefined here

Related

How to set [i] in array?

I don't know to set [i] in the array.
statusResponse() {
var dataStatus = this.$.xhrStatus.lastResponse;
for(var i = 0; i < this.maxStatus; i++) {
console.log(this.maxStatus);
console.log([i]);
console.log(dataStatus);
console.log(dataStatus[fs_+ i +_P41001_W41001B]);
this.userInfo.status({
"branch_plant": this.$.xhrStatus.lastResponse.fs_ +
[i] +_P41001_W41001B.data.gridData.rowset[0].sDescription_99.value
});
}
}
You could change:
dataStatus[fs_+ i +_P41001_W41001B]
to
dataStatus["fs_" + i + "_P41001_W41001B"]
Explaination
This is roughly how the computer understands it the following line:
Take string "fs_"
Add the variable i to it, so the string become "fs_4" (if i = 4)
Add "_P41001_W41001B" to it, so the string becomes "fs_4_P41001_W41001B"
Get dataStatus["fs_4_P41001_W41001B"]
Updated code:
statusResponse() {
var dataStatus = this.$.xhrStatus.lastResponse;
for(var i = 0; i < this.maxStatus; i++) {
console.log(this.maxStatus);
console.log([i]);
console.log(dataStatus);
console.log(dataStatus["fs_" + i + "_P41001_W41001B"]);
this.userInfo.status({
"branch_plant": this.$.xhrStatus.lastResponse["fs_" + i + "_P41001_W41001B"].data.gridData.rowset[0].sDescription_99.value
});
}
}

How to check for only checked checkboxes in an array in javascript

I am using code.org library. I am trying to use only checked checkboxes to select two teams for a baseball game. Currently I can only select 1 team but I need to select two teams effectively by not just going to the next team in the array. I have never see such problem in JavaScript.
onEvent("btnStart","click", function() {
var chkBoxs = ["Yankees","Boston","Astros"];
var index = 0;
while (index < chkBoxs.length && !getChecked(chkBoxs[index])) {
index++;
}
setScreen("game");
console.log("The Teams are: " + chkBoxs[index]+" And "+chkBoxs[index+1]);
});
Put the selected ones in a new array.
Also, remember to check that you have succeeded in finding two before you let your program continue.
Example:
onEvent("btnStart","click", function() {
var chkBoxs = ["Yankees","Boston","Astros"];
var selected = [];
for (index = 0; selected.length < 2 && index < chkBoxs.length; index++) {
if (getChecked(chkBoxs[index])) { selected.push(index); }
}
setScreen("game");
if (selected.length == 2) {
console.log("The Teams are: " + chkBoxs[selected[0]] + " and " + chkBoxs[selected[1]]);
}
});
Assuming I understand the question, you could keep track of the selected teams individually using an array:
onEvent("btnStart","click", function() {
var chkBoxs = ["Yankees","Boston","Astros"];
var indexes = [];
for (var i =0; i < chkBoxs.length; i++) {
if (getChecked(chkBoxs[index]))) {
indexes.push(index); // store team index
}
}
setScreen("game");
console.log("The Teams are: " + chkBoxs[indexes[0]]+" And "+chkBoxs[indexes[1]]);
});
This also assumes you always have two teams. Otherwise you'd have to handle the last line differently. If all you need is the team name:
onEvent("btnStart","click", function() {
var chkBoxs = ["Yankees","Boston","Astros"];
var teams = [];
for (var i =0; i < chkBoxs.length; i++) {
if (getChecked(chkBoxs[index]))) {
teams.push(chkBoxs[index]); // store team name
}
}
setScreen("game");
console.log("The Teams are: " + teams.join(', ') + ".");
});

jQuery: Display only new JSON data, iterated with its own paragraph tag

Display only new updates of JSON data, iterated with each value item in its own paragraph tag using jQuery/javascript.
If each item in the array inside the info key already is outputted in its own <p> tag; do not continue the loop but wait until there is a new item.
This is my JSON:
{
"info": [
"Hello world,",
"how are you doin?",
"Its not going to well for me unfortunately."
]
}
With this jQuery script:
function updatelog() {
$.getJSON("/static/_info",
function(data) {
$.each(data, function(key, item) {
var value = "";
var i;
for (i = 0; i < item.length; i++) {
value += item[i];
$("div").add('<p>' + value + '</p>').appendTo(document.body);
}
});
});
}
var interval = window.setInterval(updatelog, 2000);
With this I get all the items but it doesn't stop iterating. I have searched the interwebs so much that my enter key has lost all hope for salvation. I guess this is pretty easy, but I'm a beginner and also not a javascript coder and i'm ready to pull my hair off. Thanks in advance.
You could take text of all p elements and push it to new array and then check if it includes values from your object
var data = JSON.parse('{"info":["Hello world,","how are you doin?","Its not going to well for me unfortunately."]}'),
pText = [];
$('p').each(function() {
pText.push($(this).text());
});
data.info.forEach(function(el) {
if (!pText.includes(el)) {
$('body').append('<p>' + el + '</p>');
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Hello world,</p>
You can generate a hash from every list-item and use it as id in the div elements. Everytime you retrieve the data you check if the corresponding id exists. If it exists then the item is already present in your page so you don't have to append it again.
function updatelog() {
$.getJSON("/static/_info",
function(data) {
$.each(data, function(key, item) {
var i;
for (i = 0; i < item.length; i++) {
var value = item[i];
var hashCode = value.hashCode();
if(!$("body").find("#" + hashCode).length){
$("div")
.attr("id", hashCode)
.add('<p>' + value + '</p>')
.appendTo(document.body);
}
}
});
});
}
var interval = window.setInterval(updatelog, 2000);
You can use this implementation for the hashCode function.
Generate a Hash from string in Javascript/jQuery
String.prototype.hashCode = function() {
var hash = 0, i, chr, len;
if (this.length === 0) return hash;
for (i = 0, len = this.length; i < len; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};

Array is not accessible outside of Casper repeat function

My goal is to get each job link of a job site, go to each Job detail page by following Job link, download and save the detail in html through CASPERJS.
As id of each Job link change each time we back & forth between job link and job detail page, I need to get all the Job id each time under casper.repeat . But NoOfLink array is become empty outside of repeat function [I comment that part in code]. What is the problem?
var casper = require('casper').create();
var noOfRecordsToLoop = 0;
var TotalNoofNullElement = 0;
var NoOfLink = [];
var x = require('casper').selectXPath;
casper.echo('\nStart loding site......');
//---------------------------------------------Load and Scroll the site---------------------------------------//
casper.start('https://........../...../.......Careers/');
casper.wait(10000, function () {
//---------Total no of Job posting------//
var noOfRecords = this.fetchText(x('//*[#id="...........................jobProfile......"]'));
noOfRecordsToLoop = noOfRecords.replace(/[^0-9]/g, "");
var totalNoOfPage = Math.ceil(parseInt(noOfRecords) / 50);
casper.echo('\nStart scrolling site......');
casper.repeat(totalNoOfPage, function () {
this.scrollToBottom(); //-----------------------Scroll down
casper.wait(10000, function () {})
})
})
//------------------------------------------------Load and Scroll the site---------------------------------------//
casper.then(function () {
//-----------------------------------------Get all the link elements --------------------------//
var countForLink = 0;
var numTimesForRpt = noOfRecordsToLoop;
var numTimes = noOfRecordsToLoop;
casper.repeat(numTimesForRpt, function () {
RetElement = this.evaluate(function () {
var startingRow = '//*[contains(#id, "...-uid-")]'
var element = __utils__.getElementByXPath(startingRow).getAttribute('id');
return element;
});
var count = RetElement.replace(/[^0-9]/g, "");
casper.repeat(numTimes, function () {
var MatchElements = this.evaluate(function (count) {
var xp = '//*[contains(#id, "...-uid-' + count + '")]'
var element = __utils__.getElementByXPath(xp).getAttribute('id');
return element;
}, count++);
if (!MatchElements) {
TotalNoofNullElement = TotalNoofNullElement + 1
} else {
NoOfLink.push(MatchElements);
}
//**Here array elements are accessible**
for (var k = 0; k < NoOfLink.length; k++) {
this.echo(NoOfLink[k]);
}
});
//**But here array elements are not accessible outside of repeat** function
this.echo("Size of array is" + NoOfLink.length);
for (var q = 0; q < NoOfLink.length; q++) {
this.echo(NoOfLink[q]);
}
//-----------------------------------------Get all the link elements----------------------------//
//------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//
this.echo("\n Inside repeat to Generate HTML");
var num = NoOfLink[countForLink];
this.echo("\nLink id is " + NoOfLink[countForLink]);
num = parseInt(num.replace(/[^0-9]/g, ""));
this.echo("\nNum is " + num);
//-----------------Click to go to the Job Detail Page------------------//
casper.thenClick(x('//*[#id="..-uid-' + num + '"]/div/div'));
casper.wait(5000, function getJobDetail() {
var content = this.getElementInfo(x(".//*[contains(#id,'......t-uid-')]")).html;
var divStart = '<div id="extrdHtml">'
var divEnd = '</div>'
var body = divStart + content + divEnd
this.echo("\nContent of Job detail :" + body);
var fs = require('fs');
fs.write('extractedJob' + NoOfLink[countForLink] + '.html', body, 'w');
this.echo("\nFile saved");
//------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//
}); //casper.wait
casper.back();
casper.wait(5000);
countForLink++
}); //casper.repeat
}); //casper.then
//-------------------------------------------Get all the link elements------------------------------//
casper.run();
There are two repeat loops.
casper.repeat(numTimesForRpt, function () { - This is main outer loop , where the 2nd loop resides.
casper.repeat(numTimes, function () – Where I am getting the link and populating NoOfLink array. I am trying to get the array element value outside of this 2nd loop(within main outer loop) but it is not working.
All then* and wait* functions are asynchronous step functions. If you call them, you're scheduling a step that is executed at the end of the current step. casper.repeat() is a function that uses casper.then() and is therefore also asynchronous. Every synchronous code that comes after casper.repeat() will be executed before the contents of the repeat callback.
You have two options:
Wrap everything that comes after casper.repeat() in a casper.then() to make it asynchronous or
Use a normal synchronous loop instead of repeat, if the callback of repeat doesn't need to be evaluated asynchronously like in your case.
By the way, you can oftentimes reduce your code a bit by utilizing the helper functions that CasperJS provides. For example, you don't need to use evaluate() only to get the id attributes of some elements by XPath. You can do that with casper.getElementsAttribute().
Example:
var count = RetElement.replace(/[^0-9]/g, "");
for(var i = count; i < (numTimes + count); i++) {
var MatchElements = this.getElementsAttribute(x('//*[contains(#id, "...-uid-' + i + '")]'), 'id');
if (!MatchElements) {
TotalNoofNullElement = TotalNoofNullElement + 1
} else {
NoOfLink.push(MatchElements);
}
//**Here array elements are accessible**
for (var k = 0; k < NoOfLink.length; k++) {
this.echo(NoOfLink[k]);
}
}

Javascript For Loop index returning "[object Object] - undefined"

I'm trying to run one function to many elements,
so I'm using a for loop. I dont understand why i'm not getting any values.
var i;
var aFields = ["#business1A","#business1B","#business1C","#business1D","#business2A","#business2B","#business2C","#business2D",
"#business3A","#business3B","#business3C","#business3D","#business4A","#business4B","#business4C","#business4D",
"#business5A","#business5B","#business5C","#business5D","#business6A","#business6B","#business6C","#business6D"];
for (i = 0; i < aFields.length; i++) {
$(aFields[i]).keyup(function(){
alert($(aFields[i]+'Warning') + " - " +$(aFields[i]).val());
});
}
Try this:
var i;
var aFields = ["#business1A","#business1B","#business1C","#business1D","#business2A","#business2B","#business2C","#business2D",
"#business3A","#business3B","#business3C","#business3D","#business4A","#business4B","#business4C","#business4D",
"#business5A","#business5B","#business5C","#business5D","#business6A","#business6B","#business6C","#business6D"];
for (i = 0; i < aFields.length; i++) {
(function(j){
$(aFields[j]).keyup(function(){
alert(($(this).attr('id')+'Warning') + " - " +$(this).val());
});
})(i);
}
That's because you are using the variable i in the callback function for the event handler. The event happens when the loop has finished, so the variable contains an index that is beyond the last item in the array.
To use the value of the variable from the iteration where you bind the event, you can create a variable for each iteration by creating a scope, using an immediately executed function expression:
var i;
var aFields = ["#business1A","#business1B","#business1C","#business1D","#business2A","#business2B","#business2C","#business2D",
"#business3A","#business3B","#business3C","#business3D","#business4A","#business4B","#business4C","#business4D",
"#business5A","#business5B","#business5C","#business5D","#business6A","#business6B","#business6C","#business6D"];
for (i = 0; i < aFields.length; i++) {
(function(j){
$(aFields[j]).keyup(function(){
alert($(aFields[j]+'Warning') + " - " +$(aFields[j]).val());
});
})(i);
}
The problem here is the wrong usage of the closure variable i, the variable is shared between all the keyup handlers so when the loop ends i will have the value aFields.length so aFields[i] will return undefined.
Try
var aFields = ["#business1A", "#business1B", "#business1C", "#business1D", "#business2A", "#business2B", "#business2C", "#business2D",
"#business3A", "#business3B", "#business3C", "#business3D", "#business4A", "#business4B", "#business4C", "#business4D",
"#business5A", "#business5B", "#business5C", "#business5D", "#business6A", "#business6B", "#business6C", "#business6D"];
$.each(aFields, function (i, val) {
$(val).keyup(function () {
alert($(val + 'Warning') + " - " + $(val).val());
});
})
The other answers are good explanations of how closures work, but the cleanest solution is to use this to refer to the selected object:
var i;
var aFields = ["#business1A","#business1B","#business1C","#business1D","#business2A","#business2B","#business2C","#business2D",
"#business3A","#business3B","#business3C","#business3D","#business4A","#business4B","#business4C","#business4D",
"#business5A","#business5B","#business5C","#business5D","#business6A","#business6B","#business6C","#business6D"];
for (i = 0; i < aFields.length; i++) {
$(aFields[i]).keyup(function(){
alert(this.id + ' Warning - ' + this.value);
});
}

Categories

Resources