Reputation: 53318
I started off with this example from the wrapper repository.
const instance = await phantom.create();
const page = await instance.createPage();
To post an action from Node.js to PhantomJS - including emitting an event - I can do this:
await page.evaluate(function() {
// Code
}
But how about the other way around. I want to listen on an event from the page in nodeJS. I wrote this promise to wait for an event:
class PageEventPromise extends Promise {
constructor(page, event) {
super(function(resolve, reject) {
let callback = function() {
let args = [];
args.push.apply(args, arguments);
page.off(event, callback);
resolve(args);
}
page.on(event, callback);
});
}
}
I want to listen for DOM changes on particular element. I set up a MutationObserver
in the webpage context:
await page.evaluate(function() {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.type != "childList")
return;
for (var i=0,l=mutation.addedNodes.length; i<l; i++)
{
const node = mutation.addedNodes[i];
self.dispatchEvent(new Event("logEntry", {text: node.innerHTML}));
}
});
});
var config = { attributes: !true, childList: true, characterData: !true };
observer.observe(document.querySelector("div.ace_layer.ace_text-layer"), config);
});
I could see the error warnings for the errors that I throw in the setTimeout
callbacks, but the event did not trigger.
Therefore this line:
self.dispatchEvent(new Event("logEntry", {text: node.innerHTML}));
does not trigger events assigned to page
instance.
So if I assign arbitrary event:
page.on("eventName", function() {/* callback**/});
How do I trigger it from the webpage context?
Upvotes: 3
Views: 291
Reputation: 7917
UPDATE
I think this solves your problem without polling: http://phantomjs.org/api/webpage/handler/on-callback.html
Checked with phantom
module:
let phantom = require('phantom');
function nodeFnc(data) { // to be called when an event inside page occurs
console.log('data from page: '+ data);
}
(async function() {
let ph = await phantom.create();
let page = await ph.createPage();
await page.property( 'onCallback', function(data, nodeFnc) {
nodeFnc(data); // this will be called when event occurs
});
await page.evaluate( function() {
setTimeout( function() { // timeout event
window.callPhantom('from inside the page!');
}, 5000):
});
})();
====================== Polling answer ========================
While that does not answer your question directly, it may help solve your problem.
You listen to changes of DOM inside HTML and when something happens you change global variable STATUS inside that HTML from 0 to 1. From the node page you are waiting for this change with:
/**
* @param {function} checkCond - returns promise with value of ready(true or false)
*/
function wait( checkCond ) {
return new Promise( function( resolve, reject ) {
function r() {
checkCond().then(ready=>{
if ( ready === true )
return resolve();
setTimeout(function() {r();}, 1); // The condition is checked every millisecond.
});
}
r();
});
}
wait( ()=>{
return page.evaluate( function() {
return STATUS;
});
}); // returns when STATUS is true
Upvotes: 1