3

In Protractor, we can get a single element from an array by index via:

var elements = element.all(by.css(".myclass"));
elements.get(1);
elements.first();
elements.last();

But, is it possible to slice out a subarray out of the array of elements in a similar fashion?

Ideally, we'd like to have something like:

var subelements = elements.slice(2, 5);
// subelements is also an ElementArrayFinder
// we can call "filter()", "map()" etc on subelements

I think we would need to extend ElementArrayFinder by defining a custom protractor.ElementArrayFinder.prototype.slice() method (similar to how it was done here).

I've also noticed this pull request, but it has not been merged and it is not active anymore.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195

2 Answers2

3

There is no out-of-box solution i afraid. I believe you can implement slicing with .filter()

First that come to my mind:

function slice (arrayFinder, from, to) {
    return arrayFinder.filter(function(elem, index) {
        if (index >= from && index < to) {
            return true;
        }
    }
}
Xotabu4
  • 3,063
  • 17
  • 29
  • @alecxe you are welcome, btw i like to read you answers for protractor – Xotabu4 Jun 13 '16 at 15:37
  • Thanks. And I'm learning from yours. Keep posting more answers! – alecxe Jun 13 '16 at 15:40
  • 2
    Please avoid `if (...) {return true;}` when possible, it adds a level of indentation and is more complex to read for other developpers. Here, you can just use `return index >= from && index < to;`. – Thierry J. Feb 15 '17 at 21:04
1

You can use slice directly on the resolved promise:

$$('a')
  .then(elements => elements.slice(3, 8))
  .then(elements => console.log("Count ", elements.length));

You cold also extend the ElementArrayFinder prototype:

protractor.ElementArrayFinder.prototype.slice = function(begin, end) {
  return this.then(elements => elements.slice(begin, end));
};

$$('a')
  .slice(3, 8)
  .then(elements => console.log("Count ", elements.length));

And with a filter:

$$('a')
  .filter((e, i) => i >= 3 && i < 8)
  .then(elements => console.log("Count ", elements.length));
Florent B.
  • 41,537
  • 7
  • 86
  • 101
  • That wont work, since element() and element.all() return ElementFinder and ArrayElementFinder objects, not promises. So $$('a').then() will fail with no such method. .filter() also returns new ArrayElementFinder – Xotabu4 Jun 13 '16 at 21:21
  • 1
    @Xotabu4, Yes it works. The extended `.slice` returns a promise that resolves to an array of values. To make it return and ArrayElementFinder, it is as simple as wrapping the promise in a new instance of `ArrayElementFinder`. – Florent B. Jun 13 '16 at 23:26