Why doesn't this.evaluate return DOM nodes correctly?
I'm trying to get an object from a web page through the evaluate()
method so I can work with it outside the scope of evaluate
. The element selected with name symbol
is a <select>
tag with 148 <options>
(=dropdown menu).
casper.then(function () {
var elmnt = this.evaluate(function () { return document.getElementsByName("symbol")[0]; });
console.log(elmnt.options[14].index);
});
//Returns TypeError: 'null' is not an object (evaluating 'elmnt.options[14].index')
casper.then(function () {
var elmnt = this.evaluate(function () { return document.getElementsByName("symbol")[0].options[14].index; });
console.log(elmnt);
});
//Returns 14
So it looks likes returning an object through the evaluate()
method returns it incompletly since this works correctly :
casper.then(function () {
var elmnt = this.evaluate(function () { return document.getElementsByName("symbol")[0]; });
console.log(elmnt.options.length);
});
//Returns 148
So I can access options attributes as long as I don't read the array. Strange no ?
It makes sense, because elmnt.options
in the last snippet is an array full with undefined
values. So you know the number of elements, but not their values. The reason is that DOM nodes cannot be passed from page context. The docs say:
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!
So either you do everything inside of the page context (evaluate
) or you get a representation of the DOM nodes that you want to work with. Which I think is not what you want.
var elmnt = this.evaluate(function () {
return [].map.call(document.getElementsByName("symbol")[0].options, function(option){
return {text: option.innerText, value: option.value};
});
});