6

I want to understand in which case I should or have to use the evaluate function.

I have read the API doc about the evaluate function of CasperJS, but I'm unsure in which case I should use this function. And what does DOM context mean? Can somebody provide an example?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
user2521436
  • 299
  • 1
  • 5
  • 15

1 Answers1

13

The CasperJS documentation has a pretty good description of what casper.evaluate() does.

To recap: You pass a function that will be executed in the DOM context (you can also call it the page context). You can pass some primitives as arguments to this function and return one primitive back. Keep in mind that this function that you pass to evaluate must be self contained. It cannot use variables or functions that are defined outside of this function.


CasperJS provides many good functions for everyday tasks, but you may run into a situation when you need a custom function to do something. evaluate is basically there to do

  1. Retrieve some value from the page to take action based on it in your script
  2. Manipulate the page in some way other than clicking or filling out a form
  3. Combinations of points 1. and 2.

Examples

You may need a generic function to get the checked property from a checkbox. CasperJS currently only provides getElementAttribute function which will not work in this case.

function getChecked(cssSelector){
    return document.querySelector(cssSelector).checked;
}

if (casper.evaluate(getChecked, selector)){
    // do something
} else {
    // do something else
}

In most of the cases it is just preference of what you want to use. If you have a list of users with data-uid on each li element then you have at least 2 possibilities to retrieve the uids.

Casper-only:

var uids = casper.getElementsAttribute('ul#user-list > li', 'data-uid');

Casper-Evaluate:

var uids = casper.evaluate(function(){
    return Array.prototype.map.call(document.querySelectorAll('ul#user-list > li'), function(li){ return li["data-uid"]});
});

Regarding manipulation everything is possible but depends on what you want to do. Let's say you want to take screenshots of web pages, but there are some elements that you don't want to be there. Or you could add your own CSS to the document.

Remove elements:

function removeSelector(cssSelector){
    var elements = document.querySelectorAll(cssSelector);
    Array.prototype.forEach.call(elements, function(el){
        el.parent.removeChild(el);
    });
}
casper.evaluate(removeSelector, '.ad'); // if it would be that easy :)

Change site appearance through CSS:

function applyCSS(yourCss){
    var style = document.createElement("style");
    style.innerHTML = yourCss;
    document.head.appendChild(style);
}
casper.evaluate(applyCSS, 'body { background-color: black; }'); // non-sense

Roots

CasperJS is built on top of PhantomJS and as such inherits some of its quirks. The PhantomJS documentation for page.evaluate() says this:

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Where in the docs does it say that Casper.eval() only will return one primitive? Lost a lot of time not being able to figure this one out—was attempting to return an object. – nikk wong Oct 25 '15 at 08:37
  • @nikkwong All functions return only one object. That object may be an actual array which may contain many objects. The only thing is that all of it must be serializable. – Artjom B. Oct 25 '15 at 08:58
  • Sorry i'm a bit late to the party but @ArtjomB., you're saying evaluate can return array objects? Because I'm running into an error with this and I can't figure out why. – Q.H. Dec 22 '16 at 19:02
  • @Q.H. Yes, you can return primitive arrays. I've seen [your question](http://stackoverflow.com/q/41290403/1816580). It seems you haven't read the last part of my answer here. DOM nodes are not primitive, so it fails – Artjom B. Jan 14 '17 at 10:42