Why is my global variable not working? [duplicate] - javascript

I can't find out what is the problem with this JSFiddle.
HTML:
<input type="button" value="test" onclick="test()">
JavaScript:
function test(){alert("test");}
And when I click on button - nothing happened. The console says "test not defined"
I've read the JSFiddle documentation - there it says that JS code is added to <head> and HTML code is added to <body> (so this JS code is earlier than html and should work).

If you do not specify the wrap setting it defaults to "onLoad". This results with all JavaScript being wrapped in a function run after result has been loaded. All variables are local to this function thus unavailable in the global scope.
Change the wrapping setting to "no wrap" and it'll work:
http://jsfiddle.net/zalun/Yazpj/1/
I switched the framework to "No Library" as you don't use any.

The function is being defined inside a load handler and thus is in a different scope. As #ellisbben notes in the comments, you can fix this by explicitly defining it on the window object. Better, yet, change it to apply the handler to the object unobtrusively: http://jsfiddle.net/pUeue/
$('input[type=button]').click( function() {
alert("test");
});
Note applying the handler this way, instead of inline, keeps your HTML clean. I'm using jQuery, but you could do it with or without a framework or using a different framework, if you like.

There is another way, declare your function into a variable like this :
test = function() {
alert("test");
}
jsFiddle
Details
EDIT (based on the comments of #nnnnnn)
#nnnnnn :
why saying test = (without var) would fix it ?
When you define a function like this :
var test = function(){};
The function is defined locally, but when you define your function without var :
test = function(){};
test is defined on the window object which is at the top level scope.
why does this work?
Like #zalun say :
If you do not specify the wrap setting it defaults to "onLoad". This results with all JavaScript being wrapped in a function run after result has been loaded. All variables are local to this function thus unavailable in the global scope.
But if you use this syntax :
test = function(){};
You have an access to the function test because it's defined globally
References :
https://stackoverflow.com/a/338053/3083093
https://stackoverflow.com/a/5830423/3083093

Change wrap setting in the Frameworks & Extensions panel, to "No wrap-in <body>"

There is no problem with your code.Just choose the extension onLoad() from right side.

<script>
function test(){
alert("test");
}
</script>
<input type="button" value="test" onclick="test()">

Select OnDomready
HTML:
<input id="dButton" type="button" value="test"/>
JavaScript:
addEventListener('load', init, false);
function init()
{
oInput = document.getElementById('dButton');
oInput.onclick = test;
}
function test(){
alert("test");
}

Related

Why don't functions work after wrapping them in an anonymous function?

I was told to avoid public variables and conflicts, it is better to place the whole plugin in an anonymous function. I tried to do this but functions do not work anymore.
Here is a simple example:
(function($) {
function changeIt() {
$("button").text("off");
}
}(jQuery));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="changeIt()">On</button>
the function runs by a HTML element but since it is inside another function, the element cannot find it.
1- How can I make it working?
2- Is it a good approach to make sure public variables are covered and assumed as private ones?
Thanks
inline events defined on elements only have access to the global scope, so, when you moved that function out of the global scope and into the scope created by the anonymous function, it was no longer accessible to the inline event.
You have two options:
Stop using inline events
(function($) {
function changeIt() {
$("button").text("off");
}
$("button").click(changeIt);
}(jQuery));
Or define it globally
//(function($) {
function changeIt() {
$("button").text("off");
}
//}(jQuery));
This has to do with scope. The changeIt function only exists within the function($). If you want to add it to public scope its best to create an object the prototype the functions.
(function($) {}(jQuery)); -> This will create a private scope, basically your function won't be defined inside window, but inside this private scope.
<button onclick="changeIt()">On</button> -> This will try to execute changeIt from window, which will be undefined.
It's because the function is no more in the global object and thus the onclick event handler in the html element cannot find it by name.
Change your html to
<button id="mybutton">On</button>
and your code to
(function($) {
$("#mybutton").click(function(){
$("#mybutton").text("off");
});
}(jQuery));
and it will work because the handler will not need to be looked up by name
Since changeIt is not found in the global scope (window in the case of a browser), the function isn't triggered on a click. In fact, your console should show an exception like: "Uncaught ReferenceError: changeIt is not defined".
To remedy this, and keep your function structure, set the handler from within the "onload" handler:
(function($) {
$('#myBtn').on('click', function () {
$("button").text("off");
});
}(jQuery));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="myBtn">On</button>

Uncaught ReferenceError: startPause is not defined for simple button

I'm trying to create a button that sends an alert dialog box to the window but for some reason I'm getting this error: "Uncaught ReferenceError: startPause is not defined." What am I doing wrong?
Here is my fiddle: http://jsfiddle.net/rgwawupw/
And the code is here:
<button onclick="startPause()">Start</button>
$(function(){
function startPause(){
alert("A");
};
});
You have two separate problems. First, get your javascript out of your HTML. Second, startPause() is not defined in the global scope.
<button id='clicker'>Click Me!</button>
function startPause(){
alert('A');
}
$('#clicker').click(function(){
startPause();
});
Make sure you put the script tag at the end of your body element then you don't need the wrapper like you have in your code.
You don't need jQuery for this, and you should put your JS in body or head (fiddle - note the settings in the top left):
<button onclick="startPause()">Start</button>
function startPause(){
alert("A");
};
This way your function will be in global scope. When you set onLoad or onDomready in JSFiddle, you are wrapping your function in an event callback, and thus move it from global scope.
If you need or want to use jQuery, go Jared's way. That way you bind click event using jQuery and don't let the browser do it. This way you have more control and can move your function from global scope.
A function defined by a function expression inherits the current scope. That is, the function forms a closure.
On the other hand, a function defined by a Function constructor does not inherit any scope other than the global scope (which all functions inherit).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
Which means because you are not making an assignment as
$(function(){
startPause = function(){ //var was skipped purposely
alert("A");
};
});
In case you still need to use it in $(function() {}); make a global object with a namespace
var stackoverflow = {};
$(function(){
stackoverflow.startPause = function(){ //var was skipped purposely
alert("A");
};
});
<button onclick="stackoverflow.startPause()">Start</button>
but best practice would be to use
$(element).on('click', function() {});

Cannot Find JavaScript Namespace

I am trying to create namespaces in JavaScript as in the following script:
var hlAdmin = hlAdmin || {};
hlAdmin.editCompany = function (src) {
// function script
}
Then I call the function in HTML:
onclick="hlAdmin.editCompany(123)"
I get a reference error: Cannot find "editCompany".
Anyone know why?
Based on your comments I assume the following:
The equivalent script (and scoping is like):
<html><head>
</script>
var hlAdmin = hlAdmin || {};
hlAdmin.editCompany = function (src) {
// error in this script
}
</script>
</head></body>
<button onclick="hlAdmin.editCompany(123)">Caption</button>
</body></html>
In this example hlAdmin is indeed in the global scope (the root-scope of the host, called window in browsers).
If (in this example) you get reference error: Cannot find "editCompany", then one should look at other error-messages in your (browser's) error-log, because when there is a fatal error in the function for hlAdmin.editCompany, then that function will not be created (hence .editCompany becomes a property that points to undefined instead of a method that points to the function OR .editCompany doesn't even exist (depending on engine/error)).
To investigate if you indeed have a scoping-problem you could test this by: window['hlAdmin'] || (window['hlAdmin']={}); (or some equivalent variant). If that made the code work, then it seems you have some scoping-problem.
Hope these steps help someone in the future.
It's generally considered bad form to mix inline javascript and non-inline. The preferred way to do this would be to keep all the javascript in one place using an event handler:
window.hlAdmin = window.hlAdmin || {};
window.hlAdmin.editCompany = function (src) {
// function script
}
document.getElementById('yourElementId').onclick = function() {
hlAdmin.editCompany(123);
};
To more specifically address the issue: One thing that could cause this issue is if the hlAdmin object is not ending up in the global scope. You stated that this declaration is "at the top of the JavaScript file", but if it's in any kind of function (such as a function set to window.onload, or the jQuery $(function() { ... });) it would not end up in the global scope when declared as a var. A variable declared with var will only end up globally scoped if it's in the root scope, outside of any kind of function. If rather than using var hlAdmin you instead use window.hlAdmin, this will make sure that even if you're inside a document ready function or something similar, you're creating your hlAdmin in the global context, which will fix the problem if it is in fact an issue of scope.
I found the problem.
The browsers (at least Aurora and Chrome) are dropping the namespace in the onclick attribute. When you look at the browser html the namespace has just disappeared from the markup.

javascript window.open doesn't work

I want to use window.open to open a window to one of my JSP file. But the browser keeps showing connecting... And even firebug stops working every time I click the text. Neither the p nor the input tags work, but when I use a href to link the JSP it can link to the file:
<!DOCTYPE html>
<html>
<head><title>Sample JSP Page</title>
<script>
function open(){
//window.open("hello.jsp","hello","height=700, width=800");
var x=window.open("hello.jsp","window","status=1,height=700, width=800");
x.focus();
}
</script>
</head>
<body>
<h1>Sample JSP Page</h1>
<p onclick="open()">do not work</p>
<form>
<input type="button" value="new window" onclick="window.open('test-with-utils')"></form>
</body>
</html>
That's because you have redefined window.open when you defined the function open. Use a different function name instead.
Change the name of the function.
The window object is the top level object in JavaScript, and contains in itself several other objects, such as "document", "history" etc.
When you define a variable or a function of your own you really add a new property to the window object. And this will work ( and a little live example ):
var foo = "bar";
alert ( window.foo ); // says "bar"
In addition if you add this little snippet to your code:
window.onerror = function ( msg, url, num ) {
alert ( "Error: " + msg + "\nURL: " + url + "\nLine: " + num );
return true;
};
you will get this error, when press the button:
Error: Uncaught RangeError: Maximum call stack size exceeded
This means an endless recursion. It is a side effect - you define a new open function, and when you call window.open(), you recursively call your function.
Just to expand on the reason that you are having problems here, you may want to read a little about javascript Scope (Very Helpful Blog). Essentially, consider the following code:
<script>
var thisOne=true;
function thatOne() {
alert("whizbang");
}
var theOther={foo:"bar"};
//More code here...
</script>
Once you reach the comment, you know you can access those variables and the function directly, like if (thisOne) {...}, element.onclick=thatOne; or console.log(theOther.foo). However, you can also access them as children of the root object which, in a web browser, is called window. So you can do:
console.log(window["thisOne"]);
window.thatOne.call(obj, params);
console.log(window.foo.bar);
so by defining open() as a function which is not inside another element (which is to say, is inside the root element), you overwrite the window.open() function. When you attempt to call the function later on, you get problems because the open function calls window.open, which calls window.open, which calls window.open...
There's a few ways to get around this -
Define the onclick handler inline
To do this, get rid of the whole <script>..</script> element then, using whichever element you choose (that supports it) add the onclick attribute:
onclick="window.open('hello.jsp','window','status=1,height=700, width=800');"
This is a nice and quick method, and it keeps all the logic right there with it's triggering element, but it is not easily extensible and you may find yourself sneered at by some. ("Oh, you use inline javascript? how quaint")
change the method name
This will take the least effort from you in terms of getting your page working now from what you have (it's also essentially what everyone else has suggested). Just change the name of the open method to something like openANewWindow() or gotoJSP() or anything that doesn't already exist in the root object, making sure to get both where you define it (in the script element) and where you use it (in the onclick attributes).
Use a closure
This is almost definitely not what you want in this case, its more complexity than you need for a single function. Just including this as an example of how to get out of the root object, seeing as being in it seems to be the heart of your problem.
You have probably already seen in javascript how to define an object, but you may not know that by defining an object, all you are really doing is adding an object property to the root object. You can use this behavior to your advantage, to give a hierarchical structure to your functions.
For example:
<script>
var MyFunctions = (function() {
function open(){
var x=window.open("hello.jsp","window","status=1,height=700, width=800");
x.focus();
}
return {open:open};
})();
</script>
This creates an anonymous function that is immediately run. Inside the scope of this function, another function, open() is defined, however it is defined within the scope of that anonymous function, not the root object (window). After open() is defined, a reference to it is returned as the value of the object property: open.
The result of all this is that the open property of the MyFunctions object is the function you need. You can then call it with MyFunctions.open() or even window.MyFunctions.open().

javascript: call a function in a closure scope

Is there any way I can override a closure so it does part of what the original closure does? I know there's no straightforward way, but is there some hack? I'm willing to be messy...
<html>
<head>
// I DON'T CONTROL THIS CODE!!!
<script>
;(function() {
function _dothing() {
alert("_dothing");
}
function _doit() {
_dothing();
alert("_doit");
}
window.K = { doit : _doit };
})();
</script>
</head>
<body>
// I DO CONTROL THIS CODE
<script>
function mydoit() {
alert("mydoit");
_dothing(); <-- THIS FAILS, IS THERE ANY WAY TO SUCCEED? :(
}
window.K.doit = mydoit;
window.K.doit();
</script>
</body>
</html>
I think you can use jQuery to get the content of the script tag and after that you can use eval see this question.
When you put code inside this:
(function() {
})();
it's called a self invoking function, and creates a scope that you can't access (just like not being able to access a function's scope anywhere else...only inside of it) - it is run as soon as it is declared. The fact that you can call window.K.doit is because the code extends the global window object. Since you have access to window everywhere, it can be called, but only with window.K.doit or K.doit. This is how jQuery plugins are normally defined - they extend the global jQuery object without exposing any of their code directly. Sooooo no, you are not able to access it unless you do something like what the other answerer proposes - but be careful with using eval, as TECHNICALLY, any script could be inserted and you could "assume" it's right/trusted and eval it.
You can try something like this (I know this is very nasty, but, as others pointed out, it seems to be the only way):
function mydoit() {
alert("mydoit");
_dothing();
}
var f = new Function(document.scripts[0].text.replace(/(}\)\(\);\s*)$/, "window._dothing = _dothing;\n$1"));
f();
window.K.doit = mydoit;
window.K.doit();
Tested on Firefox, Chrome and IE8.
Beware: this is creating a hole new context, it's not the same as the already created.
It is calling just a copy of _dothing, not the original.
You have to create a global variable from within the anonymous / self executing function: this tutorial will show you how: http://professionalaspnet.com/archive/2012/07/29/Make-Your-JavaScript-Better-With-Self-Executing-Anonymous-Functions.aspx

Categories

Resources