8

I have a list of links that I have to simulate a click on using CasperJS. They all share the same class.

However using this.click('.click-me') only clicks on the first link.

What's the proper way of clicking on all the links? I'm thinking that maybe I should try to get the number of links via evaluate() and then use a for loop. But if I use evaluate() with the number of links I have to use messages to communicate back and that seems complicated.

Is there a better way?

Tom Zych
  • 13,329
  • 9
  • 36
  • 53
MB.
  • 4,167
  • 8
  • 52
  • 79

3 Answers3

15

I ended up using the nth-child() selector to accomplish this. Here's how...

Page:

<ul id="links">
  <li><a href="#1">1</a></li>  
  <li><a href="#2">2</a></li>  
  <li><a href="#3">3</a></li>  
</ul>

Script:

casper.then(function() {
  var i = 1;
  this.repeat(3, function() {
    this.click('#links li:nth-child(' + i + ') a');
    i++;
  });
});

You obviously don't have to use repeat but any iteration technique should work.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Tyson Nero
  • 2,048
  • 5
  • 26
  • 36
  • 1
    I consider this a better way to go, As you don't need to manipulate/remove elements from the page. Good work! – user1555863 Aug 03 '14 at 13:32
8

As proposed on the CasperJS ML and for the records, here's a possible implementation of clickWhileSelector:

var casper = require('casper').create();

casper.clickWhileSelector = function(selector) {
    return this.then(function() {
        if (this.exists(selector)) {
            this.echo('found link: ' + this.getElementInfo(selector).tag);
            this.click(selector);
            return this.clickWhileSelector(selector);
        }
        return this.echo('Done.').exit();
    });
}

casper.start().then(function() {
    this.page.content =
        '<html><body>' +
        '<a href="#" onclick="this.parentNode.removeChild(this);return false;">link 1</a>' +
        '<a href="#" onclick="this.parentNode.removeChild(this);return false;">link 2</a>' +
        '<a href="#" onclick="this.parentNode.removeChild(this);return false;">link 3</a>' +
        '</body></html>';
});

casper.clickWhileSelector('a').run();

That gives:

$ casperjs c.js
found link: <a href="#" onclick="this.parentNode.removeChild(this);return false;">link 1</a>
found link: <a href="#" onclick="this.parentNode.removeChild(this);return false;">link 2</a>
found link: <a href="#" onclick="this.parentNode.removeChild(this);return false;">link 3</a>
Done.
NiKo
  • 11,215
  • 6
  • 46
  • 56
1

Mixing the other responses, to avoid the infinite loop (this worked for me, as my items were consecutive inside a tag):

casper.clickWhileSelector = function(selector, i) {
    return this.then(function() {
        i = i || 1;
        selectorNth = selector+':nth-child(' + i + ')';

        if (this.exists(selectorNth)) {
            this.echo('found link: '+this.getElementInfo(selectorNth).tag);
            this.click(selectorNth);
            return this.clickWhileSelector(selector, i+1);
        }
        return this.echo('Done.').exit();
    });
}

Hope it helps!

Luis.

QuarK
  • 2,306
  • 1
  • 20
  • 24