If I use this:
<script>
$(document).ready(function() {
if (window.localStorage.getItem('createTicket')) {
var createTicketInfo = JSON.parse(window.localStorage.getItem('createTicket'));
}
});
</script
I see an error in the console:
Uncaught ReferenceError: createTicketInfo is not defined
But if I remove document.ready:
<script>
if (window.localStorage.getItem('createTicket')) {
var createTicketInfo = JSON.parse(window.localStorage.getItem('createTicket'));
}
</script>
Everything is ok:
Why?
It's because, in the first example, createTicketInfo is only visible within the callback (function) of ready.
function test() {
var boo = "Hi! I'm boo.";
// ...
console.log(boo); // visible here
}
test();
console.log(boo); // not visible here (even if we call test first)
In the second example, createTicketInfo is not wrapped in a function, thus it is global (visible everywhere).
if(true) {
if(true) {
if(true) {
var foo = "Hi! I'm foo.";
// ...
console.log(foo); // visible here
}
}
}
console.log(foo); // visible here too (because javascript doesn't have block scopes)
Always put in mind that javascript has function scopes, but not block scopes.
Note: As mentioned by #nnnnnn in the comment bellow, ECMAScript 6 introduced a new way of declaring variables using let or const that respect block scopes. So:
if(true) {
let zoo = "Hi! I'm zoo.";
// ...
console.log(zoo); // only visible inside this block
}
console.log(zoo); // not visible here
Something else isn't right in another section of your code.
Look at this fiddle I created.
It accurately reads and writes the value. Exactly the same code:
https://jsfiddle.net/nxka5h7y/2/
<head>
<script src = "https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
window.localStorage.setItem('createTicket', '{"a":"1"}');
$(document).ready(function() {
if (window.localStorage.getItem('createTicket')) {
var createTicketInfo = JSON.parse(window.localStorage.getItem('createTicket'));
console.log(createTicketInfo);
} else { console.log("none"); }
});
</script>
</head>
<body>
<script>
</body>
The only thing I added, was actually setting the createTicket item in localStorage, just to ensure the "if" statement inside document/ready will pass.
My semi-logical guess is that JSON stored in createTicket is malformed, based on how it was set (which is not shown in your example.) I don't really think that's the issue. But, the fact is your example produces accurate results in jFiddle. Look elsewhere in your code. Like, the part where you actually set the createTicket. Or that your jQuery is actually included, or something silly like that.
Related
I only want my JavaScript to run once, but I cannot control how many times the javascript file is executed. Basically I'm writing a tiny JS snippet into a CMS, and the CMS is actually calling it 5-10 times. So solutions like this:
function never_called_again(args) {
// do some stuff
never_called_again = function (new_args) {
// do nothing
}
}
never_called_again();
Don't seem to work because as soon as my snippet is run again from the top the function is re-declared, and 'do some stuff' is re-evaluated. Perhaps I'm just not doing it properly, I'm not great with JS. I'm considering using something like try-catch on a global variable, something like
if (code_happened == undefined) {
\\ run code
code_happened = true;
}
EDIT: There is a consistent state e.g. if I set a variable I can see when my snippet is run again. But having to declare it before I access it, I don't know how to say 'does this variable exist yet'
Try this:
var doneTheStuff;
function whatever() {
if (!doneTheStuff) {
doneTheStuff = true;
// do the stuff
}
}
Redundant variable declarations don't affect the value of the variable. Once one of the functions has set the variable to true, the others won't do anything.
if (typeof code_happened === 'undefined') {
window.code_happened = true;
// Your code here.
}
The typeof check gets you around the fact that the global hasn't been declared. You could also just do if (!window.code_happened) since property access isn't banned for undefined properties.
Use a closure, and set a flag. If the flag is true, just return:
if ( ! window.never_called_again ) {
window.never_called_again = (function () {
var ran = false;
return function (args) {
if ( ran ) return;
ran = true;
// Do stuff
};
}());
}
Here's the fiddle: http://jsfiddle.net/U2NCs/
With jQuery, the function .one() may be useful : http://api.jquery.com/one/
W3School exemple here : http://www.w3schools.com/jquery/event_one.asp
In this way, the code is executed only once.
if(typeof onceRun == "undefined") window.onceRun=(
()=>{
//your codes...
console.log("runing...")
return true
}).call()
I have a function like this:
function foo(canvas) {
canvas.mousedown(function(e) {
console.log(canvas); //undefined
});
}
I'm calling foo on mouse click in a certain spot of the page.
Why is canvas undefined?
The debugger may not show the variables in the closure until they are used.
Consider this example where the a variable is defined but never used:
(function() {
var x = 1;
$(function () {
debugger; // debugger stopped here, `x` is `undefined` in Chrome and IE but `1` in Firefox
console.log("hi");
}
})();
Same code except the variable is printed out instead of the string literal:
(function() {
var x = 1;
$(function () {
debugger; // debugger stopped here, all three browsers show `x` as `1`
console.log(x);
}
})();
Your own answer is correct, once you gave the whole code example. You encountered a quirk of Javascript known as "variable hoisting." Your code is interpreted as:
function foo(canvas) {
canvas.mousedown(function(e) {
var i, canvas; //variable declarations moved to top of function scope
console.log(canvas); //undefined
//...
for (i in array) {
canvas = array[i].canvas;
//...
}
});
}
See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
The problem was this:
function foo(canvas) {
canvas.mousedown(function(e) {
console.log(canvas); //undefined
//...
for (var i in array) {
var canvas = array[i].canvas;
//...
}
});
}
I haven't time to investigate the exact reason. My guess is that the compiler puts a "var canvas" declaration at the start of the anonymous function, such that the variable is undefined when output in the console. Otherwise don't understand it yet.
Would just like to confirm that in chrome, what Charlie said is correct. I needed to make a reference to the variable in question before I could use it within the closure, when using the debugger statement!
I'm using jqPlot to plot some points in my webApp, so I'm trying this:
var plot10 = $.jqplot ('heightChartDiv', [[3,7,9,1,5,3,8,2,5]]);
and it works fine, I this exact chart here
but when I take it out, to give it a value, like so:
$(document).ready(function(){
var serie1 = [[3,7,9,1,5,3,8,2,5]];
}
function doGraph(){
var plot10 = $.jqplot ('heightChartDiv', serie1);
}
It doesn't work. am I declaring the variable wrong? please HELP!
~Myy
Your variable scoping is all off. The variable serie1 has local scope to the anonymous function defined in $(document).ready event. Read up on javascript scope here and here.
Perhaps something like this:
// the document ready will fire when the page is finished rendering
// inline javascript as you've done with your doGraph will fire as the page renders
$(document).ready(function(){
// first define graph function
// make the series an argument to the function
doGraph = function(someSeries){
var plot10 = $.jqplot ('heightChartDiv', someSeries);
}
// now call the function with the variable
var serie1 = [[3,7,9,1,5,3,8,2,5]];
doGraph(serie1);
}
EDITS IN RESPONSE TO COMMENT
See this below example:
$(document).ready(function(){
var a = 1;
someFunc = function(){
var b = 2;
alert(a);
}
someFunc(); // this works
alert(b); // this produces an error
});
Here the variable a is considered global to the function someFunc. A variable declared in someFunc, though, does not persist outside of it.
UPDATE:
QUESTION SOLVED! I realized that the reason for this is due to 'hoisting.' Basically, the JavaScript interpreter parses the code and declares all variables (but does not initialize them) at the beginning of the function. That's why the second examples isn't working. Because JavaScript interpreter declares var changed; at the beginning of the function, but does not initialize it until it reaches the body of the code.
For function declaration like the first example, instead of JavaScript moving up just the variable name like the second example, it moves up (or 'hoists') up the entire function at the beginning of the parent function, which is why it works!
Anyway, I wrote this for personal reference and thanks for the answers...
This one works: http://jsbin.com/emarat/7/edit
$(function(){
$name = $('#test');
$name.change(changedName);
function changedName (e){
console.log('e: ', e);
console.log('e.currentTarget: ', e.currentTarget);
console.log('$(e.currentTarget).val(): ', $(e.currentTarget).val());
$('#test-display').text($(e.currentTarget).val());
}
});
but this one doesn't: http://jsbin.com/emarat/9/edit
$(function(){
$name = $('#test');
$name.change(changed);
var changed = function(e){
console.log('e: ', e);
console.log('e.currentTarget: ', e.currentTarget);
console.log('$(e.currentTarget).val(): ', $(e.currentTarget).val());
$('#test-display').text($(e.currentTarget).val());
};
});
Why?
The latter one is equivalent to:
$(function(){
var changed;
$name = $('#test');
$name.change(changed);
changed = function(e){
//...
};
});
which makes it obvious why it doesn't work. At the time of usage, the changed variable is not yet initialized (undefined).
But if you declare a function using the function yourFunctionName() syntax, it is available in the whole scope. (Which, in JavaScript, is the parent function.) Otherwise it wouldn't be possible to use functions prior to their declaration. It is called hoisting.
See also:
var functionName = function() {} vs function functionName() {}
Surprised that global variable has undefined value in JavaScript
Because the variable is defined after its use.
var a = 1;
var c = a + b;
var b = 2;
You wouldn't expect that code to run.
The first one defines a function in the scope. The second one creates a inline function and stores a reference to it in the local variable changed. The problem is that you fill the variable after you use it.
This would work:
$(function(){
var changed = function(e){
console.log('e: ', e);
console.log('e.currentTarget: ', e.currentTarget);
console.log('$(e.currentTarget).val(): ', $(e.currentTarget).val());
$('#test-display').text($(e.currentTarget).val());
};
$name = $('#test');
$name.change(changed);
});
http://jsbin.com/emarat/11/edit
I don't think I'm the first one to run into this issue but I haven't find a way to search for this without getting results that have nothing to do with the issue.
I adopted the not so extended good practice of "caching" repetitive jQuery selections into vars like var element = $('#element'); to prevent "DOM pool searching" for every repeated use of the element
The problem I'm having is that now I'm doing this caching inside a function. Something like:
function functionname (id) {
var id = $('#'+id);
//extra stuff
}
I'm not expert in variables scopes but I'm not being able to do
functionname ('some-div-id');
some-div-id.dialog('open');
So I'm pretty sure it's because the variable created inside the function is not accesible outside the function itself.
Then I came up with
function functionname (id) {
window.id = $('#'+id);
//extra stuff
}
but if I try to do window.some-div-id.dialog('open'); I get TypeError: 'undefined' is not a function
What am I missing? I'm sure it's a small dumb thing but I'm missing it just in front of my eyes.
Thanks
EDIT
Thanks everyone but you're missing something.
The code suggestions are missing the fact that the inside "global" variable name is dynamic:
var CACHEobject = {};
function doSomething (NAMEHERE) { //note the function parameter
CACHEobject.NAMEHERE = $('#'+NAMEHERE);
}
So the idea is that the function creates a javascript variable with the same name that the #element_id. If I pass a name to the function it should select the html id with that name and "cache it" to a global variable with the same name:
doSomething('myDialogOne'); doSomething('myDialogTwo');
so I can later do
CACHEobject.myDialogOne.dialog('open'); CACHEobject.myBox.dialog('close');
This is what you want (based off the edit):
var CACHEobject = {};
function doSomething(id) {
CACHEobject[id] = $('#' + id);
}
Your idea is fine. Just set up an object for that. Here's an example using STASH as the caching object:
<html>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var STASH = {};
$(document).ready(function(){
// stash your elements
STASH.item = $('#item');
STASH.otherItem = $('#otherItem');
// do stuff to them
STASH.item.css({
color: '#f00'
}); // sets #item to red
alert(STASH.otherItem.text()); // alerts foo
});
</script>
<style></style>
<body>
<div id="item">bar</div>
<div id="otherItem">foo</div>
</body>
</html>
window.some-div-id.dialog('open');
is interpreted as:
window.some - div - id.dialog('open');
i.e. subtracting, which causes three undefined variables, one of which is id.dialog which causes an error when trying to be executed as a function.
For special characters, use:
window["some-div-id"].dialog('open');
And to define:
window[id] = $("#" + id);
Anyhow, I would not advise you to use global variables. You'd better overwrite the jQuery function to implement caching (using an object with the selector as key and the matched element as value).
You could just declare the variable outside the function.
var $foo;
function some_function(id) {
$foo = $('#' + id);
}
function setDialog(selector) {
window.$dialogElem = $(selector);
//window.dialogSelector = selector;
}
var id= 'mensajes';
setDialog('#'+id);
window.$dialogElem.dialog();
//$(window.dialogSelector).dialog();
commented stuff is an alternative that takes less memory. But why the hell use window?? check this fiddle for various simple techniques.