So i have link every file needed into the index.html file :
<script src="jquery.js"></script>
<script src="notify.js"></script>
<script src="script.js"></script>
i create an object in 'notify.js' :
var notify = {
newNotification : function(text) {
}
}
script.js :
alert(notify.newNotification);
When i try to access the 'notify' object in 'script.js', it works just fine.But i want to use jquery so i add $(document).ready() to both of the file like this:
notify.js
$(document).ready (
function() {
var notify = {
newNotification : function(text) {
}
}
}
)
Script.js:
$(document).ready (
function() {
alert(notify.newNotification);
}
)
And after i add that, it comes up with notify is not defined.What's wrong? Can anyone explain why it doesn't work?
As you have defined var notify in notify.js inside $(document).ready( which is an anonymous function and var notify scope is limited to this function only .
So it is not accessible outside the $(document).ready( function
To make accessible outside don't wrap it in $(document).ready( function
like this:-
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) { }
}
});
Like everyone else here already pointed out: Only use $().ready when you're handling DOM-Elements and your Variable is not accessible because you used the var keyword (like you're supposed to). The var keyword limits the defined variables to the current scope, which is the scope of the anonymous function you use as your DOM-Ready-Handler.
So, removing the unnecessary $().read will temporary solve your problem.
BUT(!) you should wrap your code into a closures to avoid messing up the global scope and to avoid possible naming conflicts with 3rd-party code.
Like that:
notify.js
;(function ($, window, undefined) {
var notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(notify.newNotification());
})(jQuery, this);
So, now you'll have the same problem as before, you don't have access to your Object.
Sure you could just add your notify Object to the global scope as Arun P Johny suggested in his answer, but i'm pretty sure over the time there will be more Object you'll need to make global accessible.
If you put each of them in the global scope, you start messing up the global scope again, so my recommendation would be ONE global Object that will hold all other objects/variables you need globally accessible. (Or even better use something like requirejs
Somethink like this:
main.js
;var MyApp = {}; # Only variable in global scope
# Maybe some more initalization code here, dunno
notify.js
;(function ($, window, undefined) {
MyApp.notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(MyApp.notify.newNotification());
})(jQuery, this);
Some interesting Q/A's about scope and closures here on stackoverflow:
What is the scope of variables in JavaScript?
How do JavaScript closures work?
JavaScript closures vs. anonymous functions
A good Answer about messing around with the global scope:
What is meant by “leaking” into global scope?
In this case there is no need to wrap the notification object in dom ready... because from the looks of it you are not creating any dom element reference while creating the object... the only thing that matters is any method invokation that deals with dom element has to be done on dom ready.
var notify = {
newNotification: function (text) {}
}
$(document).ready(function () {
notify.newNotification()
})
if you declare the variable inside a dom ready handler then it becomes a local variable to the dom ready handler... so it will not be accessible outside the dom ready handler...
Another solution is to add the variable to the global scope within the dom ready handle like
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) {}
}
})
or
$(document).ready(function () {
window.notify = {
newNotification: function (text) {}
}
})
You only need one document.ready
And this only declare the variables that will move freely in their scripts.
See the example:
script.js:
$(document).ready(function(){
// declare the variables as global
$.varA, $.varB, $.varC;
});
notify.js:
function doNotify(){
// your code here
$.varA = /*your code here */
}
function otherFunc(txt){
// your code here
$.varB = txt;
}
All of your JavaScripts will load before the document is ready.
Create a separate function in script.js that references the notify object, then call that function from $(document).ready
Try this.
var notify = {
newNotification : function(text) {
}
Related
I have javascript file called screener.js
function ScreenerPage() {
function onScreenListChange() {
do stuff
};
}
from the index.html file I include the javascript file like this:
<script type="text/javascript" src="./js/screener.js"></script>
Then later in the head section of index.html I instantiate the screenerPage object like this:
<script type="text/javascript">
$(document).ready(function () {
screenerPage = new ScreenerPage();
}
</script>
Then down in the body section there is a select with onchange event that calls
<select id="screenList" onchange="screenerPage.onScreenListChange()">
but the browser shows error:
Uncaught TypeError: screenerPage.onScreenListChange is not a function
What am I doing wrong?
The way javascript works is it has objects and the way of which they are created matter!
Here is the way i've found that works for this kind of thing
screener.js
var ScreenerPage = function() {
this.onScreenListChange = function() {
//do stuff
console.log("test")
}
}
Later on
var a = new ScreenerPage();
a.onScreenListChange();
if you have any questions on how it works feel free to try to message me!
The reason it does not work is that you're having a scope issue.
The function ScreenerPage is defined in the global scope, meaning it is accessible anywhere. Now inside that function you define a local function called onScreenListChange.
You are able to do that, but that function only exists within the scope of the function you defined it in.
When I look at your function, I think you want to use classes. A class is a single name that can have multiple variables / methods to do a specific task.
class ScreenerPage {
constructor(text){
this.onScreenListChange(text) // Call this "method" on object creation.
}
onScreenListChange(text) {
console.log(text ? text : 'do stuff');
};
}
var a = new ScreenerPage('hi'); // now watch your console log.
a.onScreenListChange();
Sorry for the noobish question, but nothing works for me today.
I'm creating a Phonegap application and have intergrated PushWoosh API into my app. And on receive push notification I want to run my previous functions again, so the data will be updated.
Pushwoosh has JS function like this:
document.addEventListener('push-notification',
function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
var notification = event.notification;
if (typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
var object = JSON.parse(notification.u);
window.runPushFunctions(object.active, object.open); //Runs a jQuery function I have created..
}
);
Now window.runPushFunctions looks like this:
$(document).ready(function() {
window.runPushFunctions = function(active, open) {
if (active != null || active != undefined) {
$('.hubs-page').removeClass('hubs-active').hide().eq(active).show().addClass('hubs-active');
}
if (open == 2) {
$('html').addClass('hubs-opening');
}
//Trying to run functions from jQuery file that will get data from database and so on..
received();
sent();
checkFriends();
};
});
But I can't for some reason not run received(), sent(), checkFriends().
These functions is set like this in their own files like this:
(function($) {
'use strict';
function checkFriends () {
$.getJSON('url',function(data){
$.each(data,function(index,value){
//Do something with value
});
});
}
Im including files in this order:
file.js -> received(); sent();
file.js -> checkFriends();
file.js -> pushnotifications
Any help will be gladly appreciated
As the other answer here says, you are scoping your method definitions so they are not accessible anywhere outside the containing method.
(function($) {
This is a method definition. Any variables or functions non-globally declared within it cannot be accessed outside it. Therefore, you need to define the functions somewhere else or make them global for them to be accessible.
If you go for defining them somewhere else, you can simply move the function definitions to the top of the same file, outside of the (function($) {})() scope.
If you go for global definitions instead, you need to change the methods' defining lines slightly: instead of
function foo() { }
you need
window.foo = function() { }
This assigns an anonymously declared function to an object in the window scope, which is globally accessible. You can then call it using
window.foo();
or simply
foo();
since it is in the window scope.
I'm not exactly sure I'm understanding your question, but it looks to me like you are defining the function checkFriends inside of a function scope. If you need access to that function definition, you would need to declare it on an object that can be referenced from the global scope. Obviously the easiest way to do that would be to attach it to the window, though there are plenty of reasons not to do that.
window.checkFriends = function(){//code that does stuff};
What I have is something like that:
jQuery(function($) {
'use strict';
var App = {
init: function() {
App.startTool();
}
[...]
and when I try to call App.init(); from another file it say that App is not defined.
I'm trying to create some test with jasmine and I've the same error.
How can I go inside this "literal class", nested inside a simple function, from external files?
Javascript has function scope. This means that variables defined within a function are only visible within that function. To access this variable from outside the function, you'll need to either declare it outside the function, attach it to the window or some other global object directly, or return it as a value from the function.
Declaring outside:
var App;
jQuery(function($) {
'use strict';
App = {
init: function() {
App.startTool();
}
[...]
Attaching to the window or other global namespace:
jQuery(function($) {
'use strict';
window.App = { //or namespace.App where namespace can be another global variable.
init: function() {
App.startTool();
}
[...]
The way you're wrapping it you're not going to be able to return the value, but if it was a different function you could do this:
var App= (function() {
'use strict';
var App = {
init: function() {
App.startTool();
}
return App;
}())
A little more on function scope: Variables declared within a function cannot be seen from outside that function. Variables declared outside a function can be seen from inside a function. So if you want an object to be global, you need to declare it outside any function, or set it as a property on something that already has been declared outside the function. In a browser, the window object is global by default. Other environments like nodejs or rhino will have their own global objects.
Its important to understand how JS scope works because its the foundation behind a lot of the more powerful features of the language, particularly closures and the module pattern.
Some people have also mentioned the benefits of namespacing. This is a good point for this context. Having a single global variable for a library or application allows you to avoid conflicts with other libraries or scripts you might be using. You can then attach your other variables to that global namespace variable and reference them as properties of that object. So instead of calling App.init directly, call myProgram.App.init() for instance.
If it is not exposed as a global than you can not touch it.
You would have to put it into some namespace that is in the global scope.
jQuery(function($) {
'use strict';
var App = {
init: function() {
App.startTool();
}
}
if (!window.myNamespace) {
window.myNamespace = {};
}
myNamespace.App = App;
});
The fun thing here is it will not exist until document.ready, not sure why you would want it wrapped with ready. The init call should be called on ready. So you are doing to have race conditions on what widget registers first.
You need to make App globally available if you want to use it from outside the function:
jQuery(function($) {
'use strict';
// attach it to window instead of using var
window.App = {
init: function() {
App.startTool();
}
};
});
information
I am trying to build a site where I can include certain files and append to my global variable with different methods that will just add easily to the object. Meaning I only need to include the file and this page will now have access to everything in the hutber object.
core hutber.js
var hutber = {};
(function ($) {
"use strict"; //For good development standards :)
hutber.init = function(){
};
hutber.init();
})(jQuery);
extra bits hutber.form.js
(function ($) {
"use strict"; //For good development standards :)
hutber.form = {
}
});
problem
I am aware that the hutber will not have access to hutber.form as it within a closure. So without taking these out of selfexecuting functions how can I get hutber to have access to hutber.form?
Or is this just the complete wrong way to approach this?
No it will have access to hutber.form since hutber is global, but the problem is timing.
If the init() runs before the hutber.form function is executed, it will not be there. The init can not run to all of the "add-ons" are loaded.
A side note: your second one will not run since it has no (jQuery);.
(function ($) {
"use strict"; //For good development standards :)
hutber.form = {
}
}); <-- missing (jQuery); so it is not going to do anything
Run a little demo to see what happens.
var myObj = {};
(function(){
myObj.init = function(){
alert("init");
try{ //will fail since bar has not loaded yet
myObj.bar();
} catch(e){ alert("failed calling bar"); }
};
//call init before bar is loaded
myObj.init();
})();
(function(){
myObj.bar = function(){
alert("bar");
};
})();
//call init after bar has been loaded
myObj.init();
jsFiddle of above code
When you run this, you will see that the init will fail the first time it is called since bar is not loaded. The second time it will work since the method is added. So if the init depends on the loaded "modules" it needs to know when they are loaded in order to call the init method.
I think you want this:
<script src="hutber.js"></script>
<script src="hutber.form.js"></script>
<script> hutber.init(); </script>
Seeing as how you defined hutber as a global variable the "form" property will certainly be accessible within any immediately invoked function expression.
You might be looking at this the wrong way.
Not to say that immediately-invoked functions are the wrong way to build functionality...
What I am saying, however, is that you've got a globally-available object, which you're referencing directly from within your function...
After you assign hutber.form = {};, everything in whole world of the global scope has full access to hutber.form, because hutber is globally-accessible.
It really wouldn't be any different than if you went like:
//form.js
hutber = hutber || {};
hutber.form = { /* ... */ };
In terms of public access to hutber.form.
The closure covers the things you DON'T return and the things that you DON'T assign to objects/arrays/vars in an outer-scope.
So if you had var mySecretIdentity = "Jerry O'Connell"; inside of the closure, then only the methods inside of hutber.form could access mySecretItentity...
...but again, you could accomplish the same by doing something like:
// form.js
hutber = hutber || {};
hutber.form = (function () {
var mySecretIdentity = "Jerry O'Connell";
return {
submit : function () {},
clear : function () {},
validate : function () {}
};
}());
And now anything private can only be directly-accessed by the functions which were written inside of the closure.
So again, it comes down to: "What problem are you trying to solve?"
The <script> tag order is important as #Sime Vidas mentioned.
Do the following order:
<script src="hutber.js"></script>
<script src="hutber.form.js"></script>
I modified the script in jsFiddle. You'll note that I like being explicit about global variables by using window.variable. I have the init function in the core hutber.js file firing immediately, if that's what you want.
//core hutber.js
window.hutber = {}; // Explicit Global Variable
(function ($) {
"use strict"; //For good development standards :)
window.hutber.init = function(){
alert('init fired');
};
window.hutber.init(); // You can fire this anywhere since you set it on a global variable...
})(jQuery);
//Extra bits hutber.form.js
(function ($) {
"use strict"; //For good development standards :)
window.hutber.form = {prop: "hello im a form"}
alert('window.hutber.form is now' + window.hutber.form.prop);
})(jQuery);
Is it possible to load multiple scripts with same variables/functions in JS, without overriding the old value of the variable. For example to create an own scope/sandbox or object for each loaded script.
Files to load:
script1:
<script>
function init() {
do something...
}
</script>
script2:
<script>
function init() {
do something...
}
</script>
And after loading call script1.init() or script2.init(), is this possible?
You could wrap each section of code with a self invoking anonymous function, which will effectively namespace that section.
(function() {
function init() {
// do something...
}
})();
init(); // ReferenceError
However, if you can't change the code, the second init will overwrite the first definition.
However...
And after loading call script1.init() or script2.init(), is this possible?
...is confusing. Do you already have the init() as methods of an object? If so, they won't overwrite each other.
Unfortunately, no. There is a single global scope on a single page.
However, by using something like the module pattern, you can make a fake namespace:
For example:
var script1 = (function() {
var that = {};
that.init = function() {
do something...
};
more functions...
return that;
})();
And then call it by using script1.init();
You can find out more about the module pattern here.