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?
Related
I have a page with multiple buttons, each tied to the load function that are intended to open a new window and then set it customized to which button you click after the page has loaded.
I have been storing the options in objects, with the one in use under in currentTile. However, once the page loads, the text that appears says undefined, but haven't I already defined the currentTile in load()?
function tile(question, answer, points) {
this.question = question;
this.answer = answer;
this.points = points;
}
var currentTile = {};
var testTile = new tile("How are you?", "Fine", 200);
function load(tile) {
currentTile = tile;
window.open("question.html", "_self");
}
function setText() {
document.getElementById("qSlot").innerHTML = currentTile.question;
document.getElementById("value").innerHTML = "" + currentTile.points + "";
}
load() is being called like this in the html:
<td onclick="load(testTile)"></td>
Thanks in advance.
You are using window.open("question.html", "_self"); which is as good as reloading the page (assuming your current page is question.html). So when the page reloads, your JS code is going to execute all over again, including the statement var currentTile = {};. That's why you get undefined for currentTile.question and currentTile.points.
Instead of calling window.open("question.html", "_self"); call setText() directly and it will show the text properly. (Where are you calling setText() right now?).
I have been reading about Javascript Classes / Objects / Prototypes and come from a OOP background so I now wish to use Objects in Javascript.
However I think I am misunderstanding something. When using objects in the past in VB.net for example you created your object and was able to populate it by using dataclasses.
But here in the land of javascript things dont execute in the way I was expecting due to this async thing.
So I create my prototype as below and call the appropriate function but the function says it has fnished (but hasnt because it hasnt had a response from the $.post that is taking place, my code continues as null values and I dont get the info I want.
<!DOCTYPE html>
<html>
<body>
<button onclick="gogetperson()">Hello</button>
<p id="demo"></p>
<script>
function Person() {
this.firstName = '-';
this.surname= '-';
this.alias = 0;
}
Person.prototype.name = function() {
return this.firstName + " " + this.surname
};
Person.prototype.getPerson = function(personid)
{
var query = $.param({personid: personid});
var url = 'custom/person_get.php';
$.post(url, query, function (response) {
var obj = $.parseJSON(response);
this.firstname= obj['rFirstName'];
this.surname = obj['rLastName'];
this.alias = obj['rAlias'];
console.log(this.firstname);
});
}
function gogetperson()
{
var myPerson = new Person();
myPerson.getPerson(1)
console.log(myPerson.firstName);
}
</script>
<script src="plugins/jQuery/jQuery-2.1.4.min.js"></script>
</body>
</html>
So when my button runs the gogetperson function it finishes but has not got the data yet.
The console.log in the $.post section returns to the console the first name of my person but too late for me to use it.
Am I using prototypes in the wrong way?
I want to be able to use javascript as an object when getting data.
Or am I totally wrong.
My reason for wanting to use it this way was it seems the better choice over php objects.
Should I use PHP objects instead?
I ultimately want to get data from a mysql database and easily change my webpage with jquery and javascript.
You are missing one thing ,that is http call using $.post is asynchronous and it is not a blocking call. In order to get values back from getPerson() method, you have to pass a callback ( or function) in that function to get the result back but it is not a recomended approach . You can read about promises and use them because they are great.
However using a callback, you can do something like.
Person.prototype.getPerson = function(personid, cb)
{
var query = $.param({personid: personid});
var url = 'custom/person_get.php';
$.post(url, query, function (response) {
var obj = $.parseJSON(response);
var person = new Person();
person.firstname= obj['rFirstName'];
person.surname = obj['rLastName'];
person.alias = obj['rAlias'];
console.log(person.firstname);
cb(person);
});
}
And then you can call it like,
var myPerson = new Person();
function showPersonDetails(person){
console.log(person.name())
}
myPerson.getPerson(1, showPersonDetails);
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!';
};
var fbToggle = document.getElementById("fbToggle");
and later in the script
fbToggle.addEventListener("click", toggle("fbContainer"));
Console tells me that fbToggle is NULL
This is in the document though.
<input type="checkbox" id="fbToggle">
I wasnt using eventListener before, so maybe there is a special order of declaration i'm missing ?
EDIT :
entire js :
function toggle(target) {
var obj = document.getElementById(target);
display = obj.style.display;
if (display == "none") {display = "block"}
else {display = "none"}
}
function init() {
var fbToggle = document.getElementById("fbToggle");
var twitToggle = document.getElementById("twitToggle");
var pinToggle = document.getElementById("pinToggle");
console.log(fbToggle); // NULL
fbToggle.addEventListener("click", toggle("fbContainer"));
twitToggle.addEventListener("click", toggle("twitContainer"));
pinToggle.addEventListener("click", toggle("pinContainer"));
}
window.onload = init();
HTML is way too long.but JS is in head, called from external file. Also i'm not in quirk mode.
It is not clear where "later in the script" is. If it is in different scope definitely it is not going to work. Suggesting you to keep everything in a global object if possible so that you can access from different places in the script.
window.globals = {};
window.globals.fbToggle = document.getElementById("fbToggle");
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
http://jsfiddle.net/ST938/
Another point is addEventListener expects a function or function idenitifier, NOT a function call.
addEventListener("click", toggle("fbContainer")); // wrong
addEventListener("click", toggle); // correct
So if you want to pass a parameter
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
In JavaScript, putting brackets after a function name causes it to be called. If you want to reference a function without calling it you must not put brackets after the name:
window.onload = init(); // this calls init() immediately
window.onload = init; // this correctly stores init in window.onload
The same applies to toggle(). If you need to pre-specify some of the arguments you can wrap it in an anonymous function:
fbToggle.addEventListener("click", function() { toggle("fbContainer"); });
or you can use bind:
fbToggle.addEventListener("click", toggle.bind(null, "fbContainer"));
Background
Basically, this code takes all of the audio tags on the page, and when one finishes it starts the next one in the DOM.
The Issue
When fnPlay is called I receive an Illegal Invocation error.
//THIS CODE FAILS
var lastAudio = null;
$('audio').each(function(index) {
var fnPlay = $(this)[0].play;
if (lastAudio != null) {
lastAudio.bind("ended", function() {
fnPlay();
});
}
lastAudio = $(this);
});
Now I am sure that the rest of the code is fine, because the following worked.
//WORKS GREAT!
var lastAudio = null;
$('audio').each(function(index) {
var lastAudioObj = $(this)[0];
if (lastAudio != null) {
lastAudio.bind("ended", function() {
lastAudioObj.play();
});
}
lastAudio = $(this);
});
Question
Can anybody explain why I couldn't store the play() function inside my variable fnPlay and call fnPlay(), but I could store the object and call the play() function on the object?
This is because of how the context of JavaScript functions work. The context (or this) inside a function is set when it's ran, not when it's set.
When you call lastAudioObj.play();, the play() function is called in the context of lastAudioObj. Inside play(), this is lastAudioObj, so everything works.
When you do fnPlay() however, it has no context. this inside the function will be null (or window). play() doesn't like that, so it throws an exception.
There are a few ways to fix this.
One is to call the function with .call() to manually set the context.
Set the variables like:
var lastAudioObj = $(this)[0];
var fnPlay = lastAudioObj.play;
Then call:
fnPlay.call(lastAudioObj);
You can also use .bind() to set the context when setting the variable.
var lastAudioObj = $(this)[0];
var fnPlay = lastAudioObj.play.bind(lastAudioObj);
Then you can just call it like:
fnPlay();