Стажер: цикл на Promise.‹Array.‹leadfoot/Element››

Допустим, у меня есть следующая структура DOM для простоты:

<div class='myparent'>
    <div class='child'>
        <div class="label">A</div>
        <div class="ico"/>
    </div>
    <div class='child'>
        <div class="label">B</div>
        <div class="ico"/>
    </div>
    <div class='child'>
        <div class="label">C</div>
        <div class="ico"/>
    </div>
</div>

Я хотел бы зациклиться на всех элементах child, возвращаемых функцией findAllByCssSelector('.child'). В частности, я бы нажимал на подэлемент div ico ТОЛЬКО, если label div равен B.

Я бы запомнил, что findAllByCssSelector() возвращает Promise.<Array.<leadfoot/Element>>.

Обычно я должен сделать что-то вроде:

var my_label = null;
this.remote
  .findAllByCssSelector('.my-selector').then(function (elementArray) {
      for(.....) {
        elementArray[i]
            .getVisibileText()
              .then(function (text) {
                  if(text == my_label)
                    elementArray[i].findByCssSelector('.ico').click().end()
              }
      }
})

Я попробовал этот код, но он не сработал, потому что elementArray[i] в функции getVisibleText().then() не существует - как будто я теряю ссылку. Кроме того, мне также нужно, чтобы, если метка не была найдена в конце цикла, было создано исключение.

Как я могу этого добиться? Кто-нибудь может помочь, пожалуйста?


person Bruno Bruzzano    schedule 28.08.2015    source источник
comment
Так? Просто поместите цикл в обратный вызов обещания. Вы знаете, как получить доступ к массиву? Пожалуйста, опубликуйте свою текущую попытку кода (даже если он не работает)   -  person Bergi    schedule 29.08.2015


Ответы (1)


Самый простой способ сделать это — использовать выражение Xpath для прямого выбора элемента, например:

.findByXpath('//div[@class="child" and div[@class="label" and text()="B"]]/div[@class="ico"]')

Приведенное выше выражение найдет первый div с классом «ico», который является дочерним элементом div с классом «child», у которого есть дочерний div с классом «label» и текстовым содержимым «B».


Обновить

Использование выражения Xpath почти всегда предпочтительнее перебора элементов с помощью команд Leadfoot, потому что это значительно эффективнее, но если по какой-то причине требуется зацикливание, вы можете сделать что-то вроде:

var my_label = null;
this.remote
    .findAllByCssSelector('.my-selector')
    .then(function (elementArray) {
        return Promise.all(elementArray.map(function (element) {
            return element.getVisibleText()
                .then(function (text) {
                    if (text === my_label) {
                        return element.findByCssSelector('.ico')
                            .then(function (ico) {
                                return ico.click();
                            });
                    }
                });
        });
    });

Несколько ключевых моментов, на которые стоит обратить внимание:

  1. Вам нужно возвращать Promises/Commands из then обратных вызовов, когда вы выполняете асинхронные операции в then обратных вызовах.
  2. Методы элемента (например, element.findByCssSelector) возвращают обещания, а не команды, поэтому вы не можете вызвать click для результата.
person jason0x43    schedule 29.08.2015
comment
К сожалению, элементы div ico и label являются родственными элементами, как показано выше. Кроме того, я бы сказал, что приведенный выше фрагмент действительно упрощен, поскольку между child и labe|ico может быть больше разделов. Однако спасибо за старания. Кстати, здесь вопрос в том, как зациклиться на Promise.<Array.<leadfoot/Element>> и сохранить трассировку элемента, если определенное условие проверено. Я обновляю первый пост, чтобы лучше объяснить себя. - person Bruno Bruzzano; 29.08.2015
comment
Приведенный выше оператор Xpath предполагает, что элементы div ico и label являются одноуровневыми — в этом суть. Он работает с фрагментом, указанным в вопросе, и может быть легко изменен для обработки более сложной структуры. - person jason0x43; 29.08.2015
comment
@ jason0x43 извините, я не рассмотрел ваш ответ должным образом, после того, как я отредактировал свой ответ, чтобы использовать map, он стал дубликатом вашего, поэтому удалил свой :) - person mido; 31.08.2015
comment
Танки Джейсон! В конце истории я использовал селектор xpath, который намного проще, и мой код по-прежнему читабелен :) Спасибо! Тем не менее, я буду учитывать цикл массива Promise‹Element› для возможного использования в будущем. - person Bruno Bruzzano; 31.08.2015