I am using Selenium and nodejs to iterate through a html table and match a string from an array to the string in the table cell.
My array might be ["Name", "Address1", "Address2", "Address3",...] and the value in tr[1] will try to match with Arr[0], tr[2] with Arr[1] etc.
The html table will have a row for each item in the array, but if there is no data for, say, Address2 then that will not appear.
In that case, tr[3] will find that it cannot match with Arr[3]. Instead of moving to tr[4], I want to see if tr[3] matches with Arr[4], then Arr[5] etc. The items in the table will always be in the same order as the items in the array, so I have no need for any array items "unmatched".
I've posted the whole function in case it is relevant, but the issue seems very simply to be that I cannot get "i = i - 1" to carry the new value into the next loop iteration.
I have proved that I get into the Else section, and that the value of i - 1 is as I would expect at that point.
var retrieveData = function retrieveData(Arr){
j = 0
driver.findElements(webdriver.By.xpath("//*[@class='table-container']")).then (function(rows){
rowCount = rows.length;
console.log("Row count = " + rowCount);
}).then (function(fn){
for (i = 1;i < rowCount + 1; i++){
(function(i){
var element = driver.findElement(webdriver.By.xpath("//div[@class='table-container']["+i+"]/div/strong/a"));
element.getText().then(function(Type){
var typefromArray = String(Arr[j].split(':')[0]);
if (Type == typefromArray){
// Do something
j = j + 1;
} else {
// Do something
i = i - 1 // My problem looks to be here, but may be in the transfer of this back up to the beginning of the loop
j = j + 1;
}
});
})(i);
};
});
};
module.exports.retrieveData = retrieveData;
I am using Selenium and nodejs to iterate through a html table and match a string from an array to the string in the table cell.
My array might be ["Name", "Address1", "Address2", "Address3",...] and the value in tr[1] will try to match with Arr[0], tr[2] with Arr[1] etc.
The html table will have a row for each item in the array, but if there is no data for, say, Address2 then that will not appear.
In that case, tr[3] will find that it cannot match with Arr[3]. Instead of moving to tr[4], I want to see if tr[3] matches with Arr[4], then Arr[5] etc. The items in the table will always be in the same order as the items in the array, so I have no need for any array items "unmatched".
I've posted the whole function in case it is relevant, but the issue seems very simply to be that I cannot get "i = i - 1" to carry the new value into the next loop iteration.
I have proved that I get into the Else section, and that the value of i - 1 is as I would expect at that point.
var retrieveData = function retrieveData(Arr){
j = 0
driver.findElements(webdriver.By.xpath("//*[@class='table-container']")).then (function(rows){
rowCount = rows.length;
console.log("Row count = " + rowCount);
}).then (function(fn){
for (i = 1;i < rowCount + 1; i++){
(function(i){
var element = driver.findElement(webdriver.By.xpath("//div[@class='table-container']["+i+"]/div/strong/a"));
element.getText().then(function(Type){
var typefromArray = String(Arr[j].split(':')[0]);
if (Type == typefromArray){
// Do something
j = j + 1;
} else {
// Do something
i = i - 1 // My problem looks to be here, but may be in the transfer of this back up to the beginning of the loop
j = j + 1;
}
});
})(i);
};
});
};
module.exports.retrieveData = retrieveData;
Share
Improve this question
asked Feb 9, 2017 at 15:55
user7540600user7540600
331 gold badge1 silver badge3 bronze badges
3
-
1
You have the
i = i - 1
inside the IIFE. You also could usei--
andj++
. – Aureliano Far Suau Commented Feb 9, 2017 at 16:02 - Hi, thanks for the quick response! I only want to decrease the counter if the string doesn't match (i.e. the If statement returns False). How can I keep the i = i - 1(or i--) outside the Else? – user7540600 Commented Feb 9, 2017 at 16:11
-
You are shadowing the scope of the
i
in the(function(i){
declaration. – Sunshine Commented Feb 9, 2017 at 16:25
1 Answer
Reset to default 5You are using an IIFE in your for
-loop to which you pass the index.
That looks like it was designed to prevent modification of i
!
When you do
i = i - 1
at the end of your function, it has absolutely no effect as it only affects the i
inside your function.
Here's a good article about variable scopes in JavaScript.
But if you still want to modify i
, then one option would be to simply have it be returned by the anonymous function and assigned to the external i
variable:
.then (function(fn){
for (i = 1;i < rowCount + 1; i++){
i = (function(i){
var element = driver.findElement(webdriver.By.xpath("//div[@class='table-container']["+i+"]/div/strong/a"));
element.getText().then(function(Type){
var typefromArray = String(Arr[j].split(':')[0]);
if (Type == typefromArray){
// Do something
j = j + 1;
} else {
// Do something
i = i - 1 // My problem looks to be here, but may be in the transfer of this back up to the beginning of the loop
j = j + 1;
}
});
return i;
})(i);
};
That is the solution to the question you asked.
But I'm pretty sure there will be other problems in your code, as you are using a synchronous loop, yet updating the counter in an asynchronously-called function (the function passed to element.getText().then
).
I'd suggest you either study a bit about how to handle asynchronous code in JavaScript (you're using Promises right now) or open a more general question about the bigger problem you are trying to solve as there will be some more design hurdles to overe.
Here's an example of the kind of patterns you may have to use to handle multiple Promises (not meant to be copy-pasted, used ES2015 for brevity):
.then(function(fn) {
Promise.all(
Array(rowCount).fill(true).map((_, i) => i + 1) // => [1..rowCount]
.map(i => {
const element = driver.findElement(webdriver.By.xpath("//div[@class='table-container']["+i+"]/div/strong/a"));
return element.getText();
})
// Here we have an array of Promises that we pass to Promise.all
// so we can wait until all promises are resolved before executing
// the following .then
).then(types => types.filter(type => type === typefromArray)
.map(type => { /* doSomething */ });
});