Why doesn't function.apply() work across document boundaries in IE? - javascript

I'm seeing some strange behavior in IE trying to call functions in another page via function.apply().
Here's a simple test case:
test1.html:
<HTML>
<HEAD>
<script language="javascript" type="text/javascript">
var opened = null;
function applyNone() {
opened.testFunc.apply(opened);
}
function applyArgs() {
opened.testFunc.apply(opened, ["applied array"]);
}
function call() {
opened.testFunc("called directly");
}
function remoteApply() {
opened.testApply(["used remote apply"]);
}
function remoteApplyCopy() {
opened.testApplyCopy(["used remote apply copy"]);
}
function openPopup() {
opened = window.open("test2.html", "_blank");
}
</script>
</HEAD>
<BODY>
OPEN
<hr>
applyNone
applyArgs
call
remoteApply
remoteApplyCopy
</BODY>
</HTML>
test2.html:
<HTML>
<HEAD>
<script language="javascript" type="text/javascript">
function testApply(args) {
testFunc.apply(this, args);
}
function testApplyCopy(args) {
var a = [];
for(var i = 0; i < args.length; i++) {
a.push(args[i]);
}
testFunc.apply(this, a);
}
function testFunc() {
var s = "Got: ";
for(var i = 0; i < arguments.length; i++) {
s += arguments[i] + " ";
}
document.getElementById("output").innerHTML += s + "<BR>";
}
</script>
</HEAD>
<BODY>
Hi there
<div id="output"/>
</BODY>
</HTML>
In firefox and chrome all methods work properly.
In IE (tested in 6, 7, and 8) all but the applyArgs() and remoteApply() methods work as expected.
applyArgs() gives a "JScript object expected" error when it tries calling apply (test1.html line 11).
remoteApply() gives the same "JScript object expected" error when it tries calling apply (test2.html line 5).
Problem is, I need to be able to use apply(). I can get around the issue by doing something like the remoteApplyCopy() mechanism, but I'm trying to avoid that. Why doesn't apply() just work?

You need to have the arrays created in the other window, because each window has its own Array constructor. I think this will work.
Add this function to test2.html:
function getEmptyArray() {
return new Array();
}
And this function to test1.html:
Array.prototype.cloneToRemote = function (win) {
var newArray = win.getEmptyArray();
for (var i = 0; i < this.length; i++)
{
newArray.push(this[i]);
}
return newArray;
}
Then do this:
function applyArgs() {
opened.testFunc.apply(opened, ["applied array"].cloneToRemote(opened));
}
Note, it seems like you should be able to do
var newArray = new win.Array();
within the test1.html cloneToRemote() function, but I couldn't make that work. If you could do that, you could get rid of the new getEmptyArray() function in test2.html.

I have no idea why this works, but I was playing around with your code and stumbled across one solution... put test2's functions inside of test1 and it works:
<HTML>
<HEAD>
<script language="javascript" type="text/javascript">
var opened = null;
function applyArgs() {
testFunc.apply(opened, ["applied array"]);
}
function openPopup() {
opened = window.open("test2.html", "_blank");
}
function testFunc() {
var s = "Got: ";
for(var i = 0; i < arguments.length; i++) {
s += arguments[i] + " ";
}
this.document.getElementById("output").innerHTML += s + "<BR>";
}
</script>
</HEAD>
<BODY>
OPEN
<hr>
applyArgs
</BODY>
</HTML>
I'll let you know if I can figure out any more (IE is weird like that). Like I said, I was just toying with the code.

If you change test2.html testApply() function as follows:
function testApply() {
testFunc.apply(this, arguments);
}
remoteApply() works. But, applyArgs() still failed.

"...
applyArgs() gives a "JScript object expected" error when it tries calling apply (test1.html line 11).
remoteApply() gives the same "JScript object expected" error when it tries calling apply (test2.html line 5).
..."
Which exact object is not "JScript object" as "expected" ?
(hint: use debugger)
--DBJ

Related

JavaScript if statement not working except inside function. Anyone know how to fix it?

I have this function that alerts the user when their amount of "moonstone" is 10. However, for various reasons, I would like the if statement to be outside the function. When I do this though, the alert doesn't work. Could someone please explain and post a fix for it?
<!DOCTYPE html>
<html>
<img id="game-board" onclick="totalCount()" class="game-board" src="https://pics.clipartpng.com/thumbs/Mars_PNG_Clip_Art-3002.png"></img>
<h2 id="counts">Moonstone:</h2>
<script>
let stone = 0;
function totalCount() {
let newCounts = stone++;
document.getElementById('counts').innerHTML= "Moonstone:"+ newCounts;
}
if (newCounts == 10){
alert('10');
}
</script>
</html>
What does work, but that I don't want to use, is
<DOCTYPE html>
<html>
<img id="game-board" onclick="totalCount()" class="game-board" src="https://pics.clipartpng.com/thumbs/Mars_PNG_Clip_Art-3002.png"></img>
<h2 id="counts">Moonstone:</h2>
<script>
let stone = 0;
function totalCount() {
let newCounts = stone++;
document.getElementById('counts').innerHTML= "Moonstone:"+ newCounts;
if (newCounts == 10){
alert('10');
}
}
</script>
In your code you calling the totalcount() function on onclick event so whatever inside the totalcount() function will executed and code outside the totalcount() function will not execute
I'm not entirely clear why you wouldn't want the if test within the function. But, there is something that you could do:
const counter = {
value: 0,
addOne: function() {
this.value++;
if (this.value > 10) {
alert("Too many");
this.value--;
} else {
document.getElementById("counts").innerHTML = "Moonstones: " + this.value;
}
}
}
function updateCounter() {
counter.addOne();
}
<button onclick="updateCounter();">Add</button>
<div id="counts"></div>
This creates the counter as an object and includes an if test on a addOne function directly attached to that object. Whenever the updateCounter() function is called, the addOne function updates the counter value and checks to see if it has passed 10. If it has, the user gets and alert, otherwise the "counts" element gets updated.
But, as others have said, there is no real reason why an if test shouldn't be part of a function - perhaps you could explain your reasons for that requirement?

Generate a function for an event

I want to generate functions for an event by using a loop. Surely in the example below, when pressing the button, it will gives the value 100 and not 1.
<body>
<button id="b1">klickMeNow</button>
<script>
var i=1;
document.getElementById("b1").addEventListener("click", function() { alert(i);}, false);
var i=100;
</script>
</body>
I came up with this solution using a generate function:
<button id="b1">klickMeNow</button>
<script>
var i=1;
document.getElementById("b1").addEventListener("click", generate(i), false);
var i=100;
function generate(i1) {
f = function () {alert(i1);};
return f;
}
</script>
Is there a more elegant solution without writing a generate function?
Are you looking to for a simple counting function?
var count = (function() {
var c = 0;
return function() {
return ++c;
}
}());
document.getElementById('b1').onclick = function() {
alert(count());
}
<button id="b1">Click Me</button>
Oh sorry for the confusion.
If you run the first snippet it gives 100 as a result, but I want that it prints 1, the actual value when I bind the function.

Javascript function does not get passed paramrter

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script language="javascript" type="text/javascript">
(function setFont() {
var i;
for ( i = 0; i < document.all.length; i++) {
document.all[i].style.fontFamily = "Verdana";
document.all[i].style.fontSize = "16";
document.all[i].style.color="black";
}
})();
(function abc(a)
{
alert(a);
ansArray = ['a'];
for(i=1;i<=a;i++)
{
document.write('<input type = "button" value = "a">');
document.write('<input type = "button" value = "b">');
}
var myButton = document.getElementsByTagName("input");
//alert(myButton.length);
myButton[0].onclick = function() {
if(ansArray[0] == 'a')
myButton[0].style.backgroundColor = "green";
else
myButton[0].style.backgroundColor = "red";
};
myButton[1].onclick = function() {
if(ansArray[0] == 'b')
myButton[1].style.backgroundColor = "green";
else
myButton[1].style.backgroundColor = "red";
};
})();
setFont();
</script>
</head>
<body onload="abc(2)">
</body>
</html>
A javascript function abc(a) does not get the value 2 passed from <body onload = "abc(5)">. It says undefined. How to pass the parameters in a javascript function. I have posted it earlier as well but the parameter was not there, on giveing the parameter i found the problem.Please help me. Thanks in advance
Your function is a closure, it's not exposed to the public but it is executed right after it's created.
And then it's gone.
It's not there to look cool, it has its purpose. Just make normal functions to get it work
(function(a) {
// immediately called and 'garbaged'
})(a);
vs.
function publicAlwaysCallable(a) {
console.log(a); // call me when you like
}
You don't have to use immediate function in this case. Declare it like this:
function abc(a) { ... }
If for some reason you want to encapsulate your code into closure you can do it like this:
(function(export) {
export.abc = function(a) { ... };
...
})(window);
The normal function (not closure) function abc(a){ ... } with the button click handlers are to be called at the end of the script. Not on onload event of the page. Now it works in IE9 also
Thanks everybody for your valuable suggestions.

Firebug doesn’t display my javascript? can't find the error

well I want to debug some script with Firebug, (cause I can't see anything in the browser window) but when I click the script tab in Firefox it gives me the error message:
If tags have a "type" attribute, it should equal "text/javascript" or "application/javascript". Also scripts must be parsable (syntactically correct).
What am I doing wrong?
Here's my code:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script src="jquery-1.7.1.js"></script>
<script type="text/javascript">
$(function() {
/* fix: “close” the value of i inside createFunction, so it won't change */
var createFunction = function(i) {
return function() { alert(i); };
};
for (var i=0; i<5; i++) {
$('p').appendTo('body').on("click", createFunction(i));
}
})();
</script>
</body>
</html>
You must leave out the last parenthesis, I guess the code should run on dom ready?
<script type="text/javascript">
$(function() {
/* fix: “close” the value of i inside createFunction, so it won't change */
var createFunction = function(i) {
return function() { alert(i); };
};
for (var i=0; i<5; i++) {
$('<p>').appendTo('body').on("click", createFunction(i));
}
});
</script>
See here for how to make code running on dom load with jquery.
Remove parenthesis after }):
$(function() {
/* fix: “close” the value of i inside createFunction, so it won't change */
var createFunction = function(i) {
return function() { alert(i); };
};
for (var i=0; i<5; i++) {
$('p').appendTo('body').on("click", createFunction(i));
}
}); //here is the modification
In my Case I have opened firebug in other tab, So it was showing me this error.
Solution : I have closed one tab and refreshed the page. and it was working :)

Use objects method as callback

I've got another JavaScript/jQuery-Problem. A minimal example could be this: I've got a div, and want some JavaScript executed, when the mouse enters. But for some reasons (= in reality, there a many divs, and for each data needs to be kept) I want to use a object as handler for the callback. Here's a small example:
function handler($thediv)
{
this.somedata = 8;
$thediv.mouseenter(function() { this.callback(); });
}
handler.prototype.callback = function()
{
alert(somedata);
}
An object is created when the document is loaded:
$(document).ready( function() {
new handler($("div"));
});
Nothing happens - except that the constructor is executed. I've tried and searched for hours now, but I can't fix this... probably too trivial?
Edit: A complete example.
<html>
<script type="text/javascript" src="jquery-1.6.js"></script>
</head>
<body>
<div>
blah blahasdasdadsssssssssssssss
asddddddddddddddddddddddddddd
</div>
</body>
<script type="text/javascript">
$(document).ready(function() {
new handler($("div"));
});
function handler($thediv)
{
this.somedata = 8;
$thediv.mouseenter(this.callback);
}
handler.prototype.callback = function()
{
alert(somedata);
}
</script>
</html>
The biggest issue here is the use of this in various contexts. Within the mouseenter function, this refers to div, not the object.
This should work:
http://jsfiddle.net/Nx5c7/
function handler($thediv)
{
this.somedata = 8;
this.theID=$thediv.attr("id");
var obj=this;
$thediv.mouseenter(function() {
obj.callback();
});
}
handler.prototype.callback = function()
{
alert(this.theID + " : " + this.somedata);
}

Categories