Vin
Vin

Reputation: 177

How to return an element from element.all each

I am trying to return an element from a list of elements and then perform some other actions like click, drag and drop etc. I tried following code but getting error saying nodes.click() not a function

var nodes = vectorpo.yfilesCanvasMain.all(
               by.css("g text[fill-opacity='1']")
            )
            .each(function (eachnode, index) {
               eachnode.getText().then(function (text) {
                 if (text == 'hello world') {
                   return eachnode;
                 }
               })
            });

nodes.click();

Upvotes: 0

Views: 895

Answers (4)

Hubert Lin
Hubert Lin

Reputation: 211

Rather than returning eachnode, we can append eachnode to an ElementFinder[] array and return that. Then we will need to loop through the array to click each one.

// Make a reusable function
async function reusableFunction() {  
  var nodes = [];  // Change 1: Initialize local array
  vectorpo.yfilesCanvasMain
    .all(by.css("g text[fill-opacity='1']"))
    .each(function(eachnode, index) {  
      eachnode
        .getText()
        .then(function(text) {
          if (text === 'hello world') {
            nodes.push(eachnode);  // Change 2: add the node to an array
          }
        })
    });
  return nodes; // Change 3: return
}
var nodeArray = await reusableFunction(); // Change 4: function call

// Change 5: since we return an array of nodes,
//           we need to loop through the array to click each one
nodeArray.forEach(function(node) {
  node.click();
});

Upvotes: 0

Vin
Vin

Reputation: 177

After reviewed few other options I tried the following method. I am trying to find the index value of the selected element and want to return that value to my call function. But when I try to output the returned value I am getting null

function getNodeIndex () {
    var nodeIndex
    var nodes = vectorpo.yfilesCanvasMain.all(by.css("g text[fill-opacity='1']"));
    return nodes.each(function (eachNode, index) {
        // for (var i = 0; i < noOfNodes.length; i++) { //Somereason if I use for loop the i is always shows as length of the element when I try to print in below if statement
            eachNode.getText().then(function (text) {
                if (text == 'hello world') {
                    nodeIndex = index;
                    console.log("printing index value is " + nodeIndex);
                    //the nodeIndex is printing correct value
                }
            })
        return nodeIndex;
    })

And in another script I used following script

getNodeIndex().then(function(value){
  console.log("printing node index after retrieving in function ", value)
})

Here the value is printing as null. Please let me know what am I missing here.

Most of your code is correct, but a wrong on return.

A tiny change as following can fix your problem.

return nodes.each(function (eachNode, index) {
    eachNode.getText().then(function (text) {
      if (text == 'hello world') {
        nodeIndex = index;
        console.log("printing index value is " + nodeIndex);
      }
    });
})
.then(function(){
    return nodeIndex;
})

Upvotes: 0

Nitin Sahu
Nitin Sahu

Reputation: 621

As per your problem statement, You are interested in filtering out the array of elements and want to perform some action on filtered list of elements. As i stated problem and understood correctly then function 'each' is not suitable for this because 'each' function meant for iterating each element of ElementArrayFinder object hence Promise is returned and resolved after calling each elementFinder. 'each' function is used to solve different typr of problems.

So, what is the right approach to address problem you mentioned?

ElementArrayFinder class also provide function 'filter'. This function is meant for filtering out this list of elements. Therefore 'filter' function doesn't return any promise, it returns object of ElementArrayFinder after applying filter condition defined inside it. Refer following code snippet applied for the code you share.

vectorpo.yfilesCanvasMain.all(by.css("g text[fill-opacity='1']")).filter(eachNode, index){
 return eachNode.getText().then(function(text){
   return text === 'hello world';
    });
}).first().click();

Code before first().click() will again return object of ElementArrayFinder which satisfy the condition of element with 'hello world' text. That's why we used first() to get the first element from ElementArrayFinder object.

ElementArrayFinder.each() only can return null, if you stick to use each() to archive your goal, you can do as following:

var found, node;

vectorpo.yfilesCanvasMain.all(
   by.css("g text[fill-opacity='1']")
)
.each(function (eachnode, index) {
    // if had found the wanted node, end this loop in advance
    if (found) return;

  eachnode.getText().then(function (text) {
        if (text == 'hello world') {
        node = eachnode; // assign wanted node to outside variable `node`
        found = true; // change flag: found to true
        }
    })
})
.then(function() {
  // the function inside this `then()` will only be executed when above `each()` complete
  // if the ouside variable is not null or undefined,
  // means find wanted node, then click
  if (node) node.click();
});

Even you can archive same goal through each(), but it's more complex than filter(), I'd recommend to use filter()

Upvotes: 1

Ajitesh
Ajitesh

Reputation: 16

Write return nodeIndex just after closing the if statement

function getNodeIndex () { var nodeIndex var nodes = vectorpo.yfilesCanvasMain.all(by.css("g text[fill-opacity='1']")); return nodes.each(function (eachNode, index) { // for (var i = 0; i < noOfNodes.length; i++) { //Somereason if I use for loop the i is always shows as length of the element when I try to print in below if statement eachNode.getText().then(function (text) { if (text == 'hello world') { nodeIndex = index; console.log("printing index value is " + nodeIndex); //the nodeIndex is printing correct value } return nodeIndex; }); })

PS : I am using my mobile browser to type this answer so the indentation might not look ok.

Upvotes: 0

Related Questions