for loop in protractor js - javascript

I have a scenario where there are repeating elements with classname .product-tile and I am trying to get the elements by that class name and loop through each of them and finding the element whose title is Products.
If so, I'm trying clicking on apt-add-to-cart-button, but here the code isn't going in for loop.
var products = element.all(by.css('.product-tile'));
for (var i = 0; i < products.length; i++) {
console.log(i);
var product = products.get(0);
if (product.element(by.css('.productName .title')).getText() === 'Products') {
product.element(by.css('apt-add-to-cart-button')).click();
}
}
html :
Any help would be appreciated.

actually the repeating selector should be resolved as a promise like below
element.all(by.css('.product-tile.ng-scope')).then(function(items){
console.log(items.length); //will get the length here
// do the stuff here
});

Please read this through, as getText() returns a promise which needs to be resolved.
You may need something like this
var products = element.all(by.css('.product-tile.ng-scope'));
for (var i = 0; i <= products.length; i++) {
console.log(i);
var product = products.get(0);
if (product.element(by.css('.productName .title')).getText().then(function(returnText){
if(returnText==='Products'){
product.element(by.css('apt-add-to-cart-button')).click();
}else{
console.log('Something happened');
}
});
}
Edit - Your class contains compound class, so you cannot use a single class inside your CSS selector. Please see updated code

Related

Undefined is not an object in Dropdown

I want my code to show the menu by adding a slactive class and change the value of an input from ddown collection. I have some code, which isn't working as console says that on line 9 nor ddown[i], nor slitems[j] are objects, as they're undefined. How to fix this?
var slitems = document.getElementsByClassName('slitem');
ddown = document.getElementsByClassName('ddown');
for(i=0; i<ddown.length; i++) {
ddown[i].addEventListener('click', function(){document.getElementById('sl'+i).classList.add('slactive');valueChange()});
}
function valueChange(){
for(j=0;j<slitems.length;j++){
slitems[j].addEventListener('click', function(){
ddown[i].value = slitems[j].value;
document.getElementById('sl'+i).classList.remove('slactive');
});
}
}
P.S. slitems is a collection of menu elements.
Look, what you are doing has at least two flaws:
1st: when doing this: for(i=0; i < ddown.length; i++) ... you are declaring a global variable named i that, at the end of loop will have the value ddown.length; so, in valueChange, it will always have the same value
2nd: i is set to ddown.length, that is a position that doesn´t exists in the array, hence the error you got.
To fix this, set i as a local variable using var, and pass it as an argument:
var slitems = document.getElementsByClassName('slitem');
ddown = document.getElementsByClassName('ddown');
for(var i=0; i<ddown.length; i++) {
ddown[i].setAttribute("data-index", i);
ddown[i].addEventListener('click', function(e){
var i = e.target.dataset.index;
document.getElementById('sl'+i).classList.add('slactive');valueChange(i)
});
}
function valueChange(i){
for(var j=0;j<slitems.length;j++){
slitems[j].setAttribute("data-index", j);
slitems[j].setAttribute("data-index2", i);
slitems[j].addEventListener('click', function(e){
var j = e.target.dataset.index;
var i = e.target.dataset.index2;
ddown[i].value = slitems[j].value;
document.getElementById('sl'+i).classList.remove('slactive');
});
}
}
EDIT
Changed the code to add the variables used in iterators as node attributes, what should fix the variable scope issue.

Jquery .clone() method. Removing clones

I noticed some interesting behavior when dealing with the .clone() function.
If I have a function to create rows and columns dynamically like this:
function appendDiv(n) {
for (var i=0;i<n;i++) {
$rows.append($columns.clone()); //assume I put $('.rows') & others in a var
}
for (var i=0;i<n;i++) {
$wrapper.append($rows.clone());
}
}
And I then delete the elements from the DOM maybe like this:
function deleteClones() {
$wrapper.off();
$wrapper.html('');
$('body').append($wrapper);
num = prompt("Enter another number.");
return num;
}
So I'd be calling the functions in an order like this:
appendDiv(num);
num = deleteClones();
appendDiv(num);
Can someone tell me why when I call appendDiv(num); again after removing those elements, the old columns are added along with the new ones? Here is a preschool level demonstration of what I mean: http://jsfiddle.net/wj6sgeeu/. Notice upon inspecting the html document, the clones that were created before we called deleteClones() are added again when we call appendDiv(num) for the second time.
I'm new to jquery, so maybe this is a self evident and obvious fact (maybe using a different method to remove clones?) but does someone have an explanation for this behavior?
Thank you!
You need to remove the previously added columns from the row, else you are just keep adding more columns to the existing columns
function appendDiv(n) {
$rows.empty();
for (var i = 0; i < n; i++) {
$rows.append($columns.clone());
console.log('ok');
}
for (var i = 0; i < n; i++) {
$wrapper.append($rows.clone());
console.log('ok2');
}
}
Demo: Fiddle

How to match and remove an object from javascript array?

I am trying to delete an element based on string match for a object property but when I do a slice on the javascript array the array size decreases and indexes change. Please help e with a solution. Here is a jsfiddle link for the same.
Code
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
}
}
}
Add i--;
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
i--;
}
}
}
jsfiddle example
Assuming you don't have a problem with having undefined as the new value, then you could call delete[i]; instead of selection.splice(i, 1); in that case the length does not change and neither will the indices.
Both Abhi1964 and Loolooii solution seems to work fine and solve problem, but i would personally keep the filtered results in separate array instead of manipulating index/deleting value in the same array, reason being, separate array would make code look simpler to read and understand. Reviewer need not to understand the index manipulation or keep track of undefined.
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
var filteredResult = [];
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
}else{
filteredResult.push(item);
}
}
}
//use filtered result as per your need.
Note:
I have not run this code, if some error seems to be there, please feel free to edit.

Inserting html elements while DOM is changing

My code should insert HTML content in all divs that have a predefined class name, without using jQuery and at least compatible with IE8 (so no getElementsbyClass).
The html:
<div class="target">1</div>
<div class="target">2</div>
<div class="target">3</div>
<div class="target">4</div>
The javascript:
var elems = document.getElementsByTagName('*'), i;
for (wwi in elems) {
if((' ' + elems[wwi].className + ' ').indexOf(' ' + "target" + ' ') > -1) {
elems[wwi].innerHTML = "YES";
//elems[wwi].innerHTML = "<div>YES!</div>";
}
}
You can try it here.
As you can see inside each div the word YES is printed. Well the if you comment elems[wwi].innerHTML = "YES"; and replace that for elems[wwi].innerHTML = "<div>YES!</div>" the code fails. I suppose is because inserting div elements modify the DOM and in consequence the FOR cycle fails. Am i right?
Well i can solve this pretty ugly by recalling the for cycle each time i make an innerHTML, and when i insert the code i can add a class (like data-codeAlreadyInserted=1) to ignore the next time the FOR pass in that div. But again, this is pretty much a very bad solution since for an average site with many tags I can even freeze the user browser.
What do you think? lets suppose i dont know the amount of tags i insert on each innerHTML call.
"I suppose is because inserting div elements modify the DOM and in consequence the FOR cycle fails. Am i right?"
Pretty much. Your elems list is a live list that is updated when the DOM changes. Because you're adding a new div on every iteration, the list keeps growing and so you never get to the end.
To avoid this, you can either do a reverse iteration,
for (var i = elems.length-1; i > -1; i--) {
// your code
}
or convert the list to an Array.
var arr = [];
for (var i = 0, len = list.length; i < len; i++) {
arr.push(elems[i]);
}
for (i = 0; i < len; i++) {
// your code
}
Another way is to use replaceChild instead of innerHTML. It works better and it's way faster:
var newEl = elem[wwi].cloneNode(false);
newEl.innerHTML = html;
elem[wwi].parentNode.replaceChild(newEl, elem[wwi]);
You can take a copy of the live node list:
var nodes = [];
for (var i = 0, n = elems.length; i < n; ++i) {
nodes.push(elems[i]);
}
and then use a proper for loop, not for ... in to iterate over the array:
for (var i = 0, n = nodes.length; i < n; ++i) {
...
}
for ... in should only be used on objects, not arrays.

find a href with a certain value

I have an array called "selectMe" formed by a variable wich contains a string such as: 12P, 5B, 10C, etc., this is the "href" value of a hyperlink and I need to find and add the class "selected" to the ones inside this array. To break the array I have:
function selectPrevious(selections){
// split into array
var selectMe = selections.split(", ")
for (var i = 0; i < selectMe.length; i++){
$('#theater a').search(selectMe[i]).addClass('selected');
}
}
I've tried doing find() instead of search() as well as many other iterations but still haven't been able to accomplish what I want, how can I do it?
EDIT
Using one of the answers provided here I have changed it to this:
function selectPrevious(selections){
// split into array
if(typeof selections !== "undefined"){
var selectMe = selections.split(", ");
for (var i = 0; i < selectMe.length; i++){
$('#theater a[href*='+selectMe[i]+']').addClass('selected');
}
}
}
I had to add the "if(typeof selections !== "undefined")" because otherwise it was throwing me errors on IE. Anyway, I still can't add the class "selected" to the values in the array, am I missing something? or did I do something wrong?
Your selector for find() is wrong. And there are no search() in jQuery.
Instead of $('#theater a').search(selectMe[i]) use $('#theater a[href*='+selectMe[i]+']')
try this one:
function selectPrevious(selections) {
// split into array
var selectMe = selections.split(", ")
for (var i = 0; i < selectMe.length; i++){
$('#theater').find('a[href*='+selectMe[i]+']').addClass('selected');
}
}

Categories

Resources