How to access functions in injected .js files from evaluate()? - javascript

Is it possible to reference functions in an embedded JavaScript file, when calling page.evaluate() using PhantomJS?
e.g. I would like to call a function someFunctionInMyJs included in the file my.js:
var page = require('webpage').create();
page.injectJs('my.js')
page.open('http://...', function() {
var x = page.evaluate(function() {
var y = someFunctionInMyJs();
return y;
});
phantom.exit();
});
Is that possible/are there alternative approaches?
my.js looks like this:
function someFunctionInMyJs() {
return 'Hi there!';
}
and the error I'm getting is:
ReferenceError: Can't find variable: someFunctionInMyJs
my.js lies in the folder where I'm invoking PhantomJS.

The problem is that you inject a script into the page which is about:blank at this point and then open your intended page. You need to inject your script inside of the page.open callback. You will have to do this every time you navigate to another page.
page.open('http://...', function() {
page.injectJs('my.js')
var x = page.evaluate(function() {
var y = someFunctionInMyJs();
return y;
});
phantom.exit();
});
You can also try to inject (injectJs) your script from through the page.onInitialized handler, if your script for example exchanges the implementation of XMLHttpRequest.
If this still doesn't work, it is possible that your function isn't global in which case you have to make it so. Edit my.js to define your function as
window.someFunctionInMyJs = function() {
return 'Hi there!';
};

Related

Accessing an Immediately Invoked Function Expression variable in Node.js in another file using require

File 1 - Monitor.js
var MONITOR = (function () {
// File Content
return {
doThing: function() {
doThing();
}
};
})();
File 2 - Test.js
var monitor = require('../public/js/monitor.js');
I want to access doThing() in File 2. I have tried various syntax and no luck so far.
From the frontend HTML I can simply include Monitor.js in a script tag, and call MONITOR.doThing(); without trouble but in Test.js this is proving difficult.
Any advice on how?
You have to export MONITOR so that someone else can access it with require().
Add this:
module.exports = MONITOR;
at the bottom of Monitor.js.
And, if you want the monitor.doThing() method to return some value, then you have to add a return statement to the function as in:
var MONITOR = (function () {
// File Content
return {
doThing: function() {
return "hello";
}
};
})();

Calling a JavaScript function from shiny server

I want to call a javascript function, display in my case, from server.R with one parameter. The print statement below the call is getting executed, but the javascript function is not getting executed. Is this the right way of calling js function?
observe ({
if (is.null(input$location))
return()
tags$script(type="text/javascript", src = "datadisplay.js")
tags$script(JS('display(today_trends))'))
print(today_trends[1])
})
}
My js file:
function disp(params) {
var myWindow = window.open("");
myWindow.document.write("New window");
}
I've also tried js$display(today_trends) this way, but I get an error: Attempt to apply non-function.
Modified js file:
shinyjs.display = function(params) {
var myWindow = window.open("");
myWindow.document.write("New window");
};

external JavaScript function not triggered in HTML <script>

I know this question has been already addressed here but that workaround does not work in my case.
I have a function in an external JavaScript that I would like to call immediately after the page is loaded. This is the snippet in the external code to be executed
var user_id = "";
var obj = obj || {};
obj.Id = {
assignId : function(id) {
console.log(id);
user_id = id;
window.alert("ID no:" + user_id);
return user_id;
}
}
and this is the HTML
<script>
obj.Id.assignId("a string");
</script>
I also tried this way
<script>
window.onload = function() {obj.Id.assignId("a string");}
</script>
but window.onload is called afterwards in the external file so I think it was overridden as described in this question.
Here is what I get from the console in both previous cases:
Uncaught ReferenceError: obj is not defined
When using this way:
window.onload = function() {
obj.Id.assignId("UA-0001");
}
I don't get any error but the function is not triggered though.
What I'm not able to figure out is: if prompting directly in the console obj I get Object {Id: Object} and if prompting obj.Id.assignId("a string") I get exactly what I want.
Is there any explanation for this?

How to pass an object to a CasperJS function

I'm writing some test code for work and am trying to figure out why it throws an error. I'm using an object oriented approach to this so to keep my main script as clean as possible. I have one script that contains all my element paths called elements.js. I'm using phantom to inject that script into another file that contains click methods called click.js. Example:
function Click() {
phantom.page.includeJs('/my/path/to/elements.js');
var element = new Elements();
this.clickElement = function() {
casper.then( function() {
casper.click(element.nameOfElement);
});
};
}
Running my script this way throws undefined errors, however if I directly declare the element's path in my click.js script, my test runs fine:
function Click() {
var nameOfElement = ('css > path > to > element');
this.clickElement = function() {
casper.then( function() {
casper.click(nameOfElement);
});
};
}
I'm wanting to call all element paths from one source just to keep my scripts clean, as you can imagine they can get long depending on how many elements we're testing. I also have other files that require the use of an element's path for this test, but they follow the same principle as the piece of my click.js script above.
UPDATE
Here is what my element.js script looks like:
function Elements() {
var nameOfElement = ("css path");
var anotherElement = ("css path");
}
PhantomJS (and CasperJS) has two contexts. page.includeJs() and page.injectJs() are two PhantomJS functions that include a JavaScript file into the DOM which is then evaluated in the page context, but you want to access your elements paths outside of the page context.
I assume your elements.js looks like this:
function Elements(){
this.someElement = "css path";
...
}
then you need to read the file and evaluate it:
var fs = require("fs");
var el = fs.read("/path/tp/elements.js");
eval(el);
var elements = new Elements();
console.log(elements.someElement);
You probably should define your elements.js differently to leverage PhantomJS's require capability:
As module
elements.js
module.exports = function(){
this.someElement = "css path";
...
}
script.js
var elements = new require("/path/to/elements.js");
As object
elements.js
exports.someElement = "css path";
exports.someOtherElement = "css path";
script.js
var elements = require("/path/to/elements.js");
You probably don't want to read the file on every click, so you can
var elements = require("/path/to/elements.js");
casper.clickElement = function(nameOfElement) {
this.thenClick(elements[nameOfElement]);
};
and use it later like this
casper.clickElement("someOtherElement");
I solved this by getting through a rookie brain fart I was in. In my element.js script, I added a simple get method and it works now.
function Elements() {
var someElement = "css path";
this.getSomeElementPath = function() {
return someElement;
};
}
Called it in my click.js script as:
function Click() {
phantom.page.injectJs('path/to/element.js');
var element = new Elements();
this.clickSomeElement = function() {
casper.then( function() {
casper.click(element.getSomeElementPath());
});
};
}
And, in my main script:
'use strict':
phantom.page.injectJs('/path/to/element.js');
phantom.page.injectJs('/path/to/click.js');
var element = new Element();
var click = new Click();
casper.test.begin("Test", function (test) {
var url = www.url.com;
console.log(url);
casper.start(url);
casper.then(function() {
click.clickSomeElement();
});
....//rest of code
casper.run(function() {
casper.test.done();
});
});
Now, the test runs as it should.

Calling a JavaScript function from another function in a different JS file

I have a web page displaying an HTML5 canvas. When the web page loads, the following JavaScript function is called:
window.onload = function(){
var sources = {};
sources[0] = document.getElementById("building").src,
sources[1] = document.getElementById("chair").src,
sources[2] = document.getElementById("drink").src,
sources[3] = document.getElementById("food").src,
sources[4] = document.getElementById("fridge").src,
sources[5] = document.getElementById("land").src,
sources[6] = document.getElementById("money").src,
sources[7] = document.getElementById("oven").src,
sources[8] = document.getElementById("table").src,
sources[9] = document.getElementById("van").src,
sources[10] = document.getElementById("burger").src,
sources[11] = document.getElementById("chips").src,
sources[12] = document.getElementById("drink").src,
sources[13] = document.getElementById("franchiseFee").src,
sources[14] = document.getElementById("wages").src,
sources[15] = document.getElementById("admin").src,
sources[16] = document.getElementById("cleaners").src,
sources[17] = document.getElementById("electricity").src,
sources[18] = document.getElementById("insurance").src,
sources[19] = document.getElementById("manager").src,
sources[20] = document.getElementById("rates").src,
sources[21] = document.getElementById("training").src,
sources[22] = document.getElementById("water").src,
sources[23] = document.getElementById("burger").src,
sources[24] = document.getElementById("chips").src,
sources[25] = document.getElementById("drink").src,
sources[26] = document.getElementById("creditors").src,
sources[27] = document.getElementById("electricity").src,
sources[28] = document.getElementById("food").src,
sources[29] = document.getElementById("hirePurchase").src,
sources[30] = document.getElementById("loan").src,
sources[31] = document.getElementById("overdraft").src,
sources[32] = document.getElementById("payeTax").src,
sources[33] = document.getElementById("tax").src
loadImages(sources, drawImage);
drawGameElements();
drawDescriptionBoxes();
};
This function loads some images from the hidden section of the HTML into the JavaScript, and draws them to the canvas by calling the 'drawImage()' function on each image in the 'sources' array. It then calls the 'drawGameelements();' function, which draws a few more things to the canvas, and finally, I then want to call the 'drawDescriptionBoxes()' function.
This function however, is in a separate JS file to the rest of the code, and when I view the page in a browser, although 'loadImages()' and 'drawGameElements()' are called, and draw what they're supposed to to the canvas, I get an error in the console saying:
ReferenceError: drawDescriptionBoxes is not defined
which I assume means that I haven't referenced the function correctly, since it's not in the same file as where I'm calling it.
What I'm wondering is how do I call this function from the other file? Would it be something like: filename.js.drawDescriptionBoxes ?
There's really two possibilities why the drawDescriptionBoxes function is undefined.
1) It's out of scope
In JavaScript, variables exist in some sort of scope. This maybe global, such as:
<script>
var foo = 123; //foo can be referenced anywhere, it's global!
</script>
Or scoped within another block of code:
function myFunc()
{
var bar = function () //bar can only be accessed within myFunc
{
};
};
//bar() here is undefined
There's a possibility your drawDescriptionBoxes function is not in the global scope.
2) It's not yet defined when your code runs
It's also possible you have some code like this:
File 1
<script>
var result = someFunc(123);
</script>
File 2
<script>
function someFunc(x)
{
return x * 2;
}
</script>
If File 2 gets included after File 1, someFunc doesn't yet exist when file 1 is run. You can get around this by running everything after the document fully loads, using event handlers. If var result = someFunc(123); was run in the onload event, it would work fine regardless of what file someFunc was defined in.
Hope this helps!
if drawDescriptionBoxes is defined as a global function, such as
function drawDescriptionBoxes() {
}
then the fact that it is not found means that the javascript file containing it did not load. Show how you include this file in html and how the function is defined.

Categories

Resources