I have made a lot of functions. I put these functions in a script.js file. But all these functions are loading on every page.
I have made the functions like this:
$(function () {
}):
But how can I ensure that the functions are not loading on every page?
That I can call only the function that I need?
Paul Irish has a nice way of dealing with that problem. See his article:
Automate firing of onload events
You can basically create an structure for each of your pages like this:
var siteNameSpace = {
homepage : {
onload : function(){
// do this stuff.
}
},
contact : {
onload : function(){
// onload stuff for contact us page
}
}
};
And respective page's code will fire only with:
$(document).ready( siteNameSpace[ document.body.id ].onload );
For that, you need to assign an id to body tag of each of your pages:
<body id="home">
<body id="contactUs">
and so on
One way would be to split the .js files into modules, and only include the .js files that are relevant to the page.
In jQuery, it is perhaps more common to use an approach such as this:
$(function () {
if (someCheck) {
// do something
}
if (someCheck) {
// do something else
}
});
The someChecks are usually checking that a specific element exists (if ($(someSelector).length)).
However, to specifically answer your question, you'd give the functions a name and then call them, so instead of having;
$(function () {
// do foo
})
You'd have
function someName() {
// do foo
}
and then you can call the function like someName(), but obviously you'd need to put the function call in a place which you could control on per-page basis (such as in the <head> of the page, or by including different .js files as explained earlier in the answer.
You can create few sets of external javascript files, place them in page wherever they are required.
Alternatively you can load script using jQuery's getScript method;
$.getScript('url of ext js', function(data, textStatus) {
});
I can't really understand what you're exactly asking for, but maybe I can clear some things out for you.
It doesn't matter if variables (functions) are declared in different files, what does matter is in what scope they are declared.
In other words, even if the functions are in different files, if they're declared global (not inside a closure/function/object), they are visible and can be called from anywhere.
Ex of global functions:
function foo() {/*...*/}
var bar = function(){/*...*/}
window.func = function(){/*...*/}
If you want to "hide" the functions, making them inaccessible from a different scope, you should use a closure.
Ex of functions defined in closure:
function initialise {
var foo = function(){}
function bar(){}
alert(typeof foo); // function
alert(typeof bar); // function
// foo & bar are visiblehere
}
alert(typeof foo); // undefined
alert(typeof bar); // undefined
// foo & bar are undefined here
More over, if you want to execute them only once and completely make them inaccessible, you can wrap them in a self executing function :
(function(){
function bar(){}
alert(typeof bar);// function
// bar is visible here
})();
// bar is undefined here
I don't know if I answered your question, but I hope info this helps.
Related
I am newbie in js and I want to override/overwrite some fullcalendar functions from another script (my-fullcalendar.js) to make some changes in it for myself. for example function names are :
formatRange and oldMomentFormat.
formatRange is accessible from this.$.fullCalendar.formatRange but oldMomentFormat is not accessible via this kind of chain. But even when I do something like this in my-fullcalendar.js:
;(function () {
function MyformatRange(date1, date2, formatStr, separator, isRTL) {
console.log( "MyformatRange");
//other parts is exactly the same
// ...
}
this.$.fullCalendar.formatRange=MyformatRange;
console.log(this);
})();
nothing happens because no log is generated and even line by line tracing does not pass from here. but when observing "this" in console log MyformatRange replaced by original formatRange.
another problem is how can I override/overwrite oldMomentFormat function which is not in window hierarchy to access (or I can not find it) ??
OK, let's simplify the problem. In essence, you have this situation:
var makeFunObject = function () {
var doSomething = function (msg) {
console.log(msg);
};
var haveFun = function () {
doSomething( "fun!");
};
return {
doSomething : doSomething,
haveFun : haveFun
};
};
In other words you have a function that is creating a closure. Inside that closure are two "private" functions, one of which calls the other. But both functions seem to be "exposed" in the returned object.
You write some code:
var myFunObject = makeFunObject();
myFunObject.haveFun(); // fun!
Yep, seems to work just fine. Now let's replace the doSomething function in that returned object and call haveFun again:
myFunObject.doSomething = function (msg) {
console.log("My new function: " + msg);
};
myFunObject.haveFun(); // fun! <== wait what?
But wait! The new replacement function is not being called! That's right: the haveFun function was expressly written to call the internal function. It in fact knows nothing about the exposed function in the object at all.
That's because you cannot replace the internal, private function in this way (you cannot replace it at all, in fact, not without altering the original code).
Now draw back to the FullCalendar code: you are replacing the external function in the object, but the internal function is the one that is called by every other function inside FullCalendar.
I realize this is an old question, but I was butting my head against this same problem when I wanted to override the getEventTimeText function.
I was able to accomplish this, from inside my own JS file, like so:
$.fullCalendar.Grid.mixin({
getEventTimeText: function (range, formatStr, displayEnd) {
//custom version of this function
}
});
So, in terms of the function you were trying to override, you should be able to do it with:
$.fullCalendar.View.mixin({
formatRange: function (range, formatStr, separator) {
//custom formatRange function
}
});
Note: Make sure this runs before where you actually create the calendar. Also note that you need to make sure to override the function in the right place. For example, getEventTimeText was in $.fullCalendar.Grid, while formatRange is in $.fullCalendar.View.
Hopefully this helps other people who end up on this question.
WARNING!! I AM A NOVICE THROUGH AND THROUGH
Alright, so I know there have been a lot questions about Global variables, and I think that's what I'm looking for, but, not exactly. Lately I've been needing to call upon the same lines of code several times. document.getElementById("example").style or similar to little things like that but I need to continuously repeat.
My question is how do I make it so that I make one variable, outside of the function, to save time writing these lines?
What I've been seeing is to simply write it outside like this var inferno = document.getElementById("inferno"); but this is far from working.
This is my code right now, it's simple because I was just using it as a test, but can anyone help me?
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
You have the right idea. Note, though, that the variable doesn't have to be global. It just has to be where all of the code that wants to use it can use it.
For example, this creates a global:
<script>
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
</script>
(Note that this needs to be after the markup creating the inferno element.)
The problem with globals is that they can conflict with each other, and in fact the global "namespace" is really, really crowded already.
You can avoid that by wrapping up the code that needs inferno in a scoping function, like this:
<script>
(function() {
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
})();
</script>
That code creates an anonymous function and then calls it immediately, running the code inside.
Now inferno is "global" to the functions that need it, but isn't actually a global.
Let's take a further example:
<script>
(function() {
var outer = 42;
function doSomethingCool() {
var inner = 67;
document.getElementById("someElement").onclick = function() {
alert("inner = " + inner + ", outer = " + outer);
};
}
// Can't use `inner` here, but can use `outer`
alert("outer = " + outer);
doSomethingCool();
})();
</script>
That code wraps everything in a scoping function, and the outer variable is accessible everywhere within that scoping function. It also has a function, doSomethingCool, which has a variable called inner. inner is only accessible within doSomethingCool. Look at what doSomethingCool does: It hooks up an event handler for when someElement is clicked. It doesn't call the function, it just hooks it up.
The really cool thing is that later, when someone clicks the element, that function has access to that inner variable.
And in fact, that's true for arguments you pass into the function as well. One last example:
<input type="button" id="element1" value="One">
<input type="button" id="element2" value="Two">
<script>
(function() {
function hookItUp(id, msg) {
document.getElementById(id).onclick = function() {
alert(msg);
};
}
hookItUp("element1", "This message is for element1");
hookItUp("element2", "And this one is for element2");
})();
</script>
There, we have this function that accepts a couple of arguments, and we call it twice: Once to hook up click on element1, and again to hook up click on element2.
The really cool thing here is that even though the clicks happen much later, after the calls to hookItUp have long-since returned, the functions created when we called hookItUp still have access to the arguments we passed to it — when we click element1, we get "This message is for element1", and when we click element2, we get "And this one is for element2."
These are called closures. You can read more about them on my blog: Closures are not complicated
That'll work, but only if the declaration appears after the point in the DOM where the element actually appears. Try moving your <script> to the very end of the <body>.
Another thing you can do is use the window "load" event to make sure the whole DOM has been seen before your code runs.
for example
var myGlobalVars = {"inferno":null,"othervar":null}; // globals in their own scope
function clickMe(varName,color) { // generic function
myGlobalVars[varName].style.backgroundColor=color;
}
window.onload=function() {
// initialise after the objects are available
for (var o in myGlobalVars) myGlobalVars[o]=document.getElementById(o);
// execute
clickMe("inferno","red");
}
.
.
T.J. Crowder gave a beautiful answer about scoping; just to add on that you can also use an immediately-invoked function expression to create a module with your UI elements, i.e.
var UI = (function() {
...
return {
inferno: document.getElementById("inferno");
};
})();
...
UI.inferno.style = ...;
I am using Phonegap and JQueryMobile to create a web application. I'm new to javascript and am having an issue.
My issue is with calling a function I have in a file named "testscript.js", the function is called testFunc. The testscript.js containts only this:
function testFunc() {
console.log("Yes I work");
}
Within my html page I have the following code:
<script>
$('#pageListener').live('pageinit', function(event)
{
testFunc();
});
</script>
The test function is found within my "testscript.js" which I am including with this line within the head tags:
<script src="testscript.js"></script>
The error I get is a "testFunc is not defined".
I am assuming its some type of scope issue as I'm able to call other jquery functions such as:
alert("I work");
and I am able to call my functions by sticking them within script tags in the html elsewhere.
I've tried all sorts of ways of calling my function with no success, any help is appreciated!
You must include the testscript.js before the other jquery code in your html. Like this:
<script src="testscript.js"></script>
<script>
$('#pageListener').live('pageinit', function(event)
{
testFunc();
});
</script>
As long as testscript.js has been loaded by the time PhoneGap fires the pageinit event, and provided the testFunc function is a global, there's no reason that shouldn't work.
You haven't shown us your testFunc, but my guess is that it's not a global, but rather you have it inside something like, for instance:
$('#pageListener').live('pageinit', function(event)
{
function testFunc()
{
// Do something here
}
});
or just a scoping function
(function()
{
function testFunc()
{
// Do something here
}
})();
Either way, since it's declared within another function, it's local to that function, not global. To call it from another script file, you'll need to be able to get at it from the global namespace (sadly). The best way to do that is not to make it a global, but to create just one global that you'll put all of your shared stuff on, like this:
(function()
{
if (!window.MyStuff)
{
window.MyStuff = {};
}
window.MyStuff.testFunc = testFunc;
function testFunc()
{
// Do something here
}
})();
...which you call like this:
$('#pageListener').live('pageinit', function(event)
{
MyStuff.testFunc(); // Or: window.MyStuff.testFunc();
});
Simplified Example:
// path/to/js/panel.js
$(function(){
var hidePanel = function(){
//hides the panel div
};
});
// path/to/js/another-script.js
$(function(){
hidePanel(); //out of scope MEGA-FAIL
});
As we speak, i have some functions/variables copy-pasted in 2 different files.
I was curious whether RequireJS would solve this problem...
Your function itself just needs to be declared after jQuery is loaded if it needs jQuery, but it need not be declared on document.ready, just executed then. The simplest way to do what you're after is:
// path/to/js/panel.js
function hidePanel() {
//hides the panel div
}
// path/to/js/another-script.js
$(hidePanel);
This just passes your function to $(), which schedules it run on document.ready, or immediately if the document is already ready.
// path/to/js/panel.js
$(function(){
var hidePanel = function(){
//hides the panel div
};
});
With this code you create an an anonymous function. Anonymous functions don't pollute the global namespace. All variables (in this case hidePanel) declared in an anonymous function are not visible outside of the anonymous function.
Because of that the function is not available.
So you need to do a global function.
You can make that in different ways:
var hidePanel = function() {
});
function hidePanel() {
}
P.S: I recommend that you learn the OO-Pattern for javascript :-)
Javascript Object-Oriented Programming | Part 1
I have a 2000 line jquery file, I just broke up the file into smaller ones, If I have a function in the first file, that file # 2 is referring to, it's coming up undefined.
Every file is is wrapped in a jquery ready function, What's the best way to do this?
If the function in question is declared within the scope of the ready handler, it won't be accessible to any other code, including other ready handlers.
What you need to do is define the function in the global scope:
function foo()
{
alert('foo');
}
$(document).ready(function()
{
foo();
});
P.S. A more concise way of adding a ready handler is this:
$(function()
{
foo();
});
Edit: If the contents of each of your divided ready handlers rely on the previous sections, then you can't split them up, for the reasons outlines above. What would be more sensible would be to factor out the bulk of the logic into independent functions, put these in their own files outside the ready event handler, and then call them from within the handler.
Edit: To further clarify, consider this handler:
$(function()
{
var foo = 'foo';
var bar = 'bar';
alert(foo);
alert(bar);
});
I might then split this up:
$(function()
{
var foo = 'foo';
var bar = 'bar';
});
$(function()
{
alert(foo);
alert(bar);
});
The problem with this is that foo and bar are defined in the first handler, and when they are used in the second handler, they have gone out of scope.
Any continuous flow of logic like this needs to be in the same scope (in this case, the event handler).
Function definition should not be wrapped in another function. Not unless you really want that function definition to be private. And if I understand correctly that's not your intention.
Only wrap function invocation in the jQuery ready function.
If you're worried about your functions clashing with third party function names then namespace them:
var myFunctions = {}
myFunctions.doThis = function () {}
myFunctions.doThat = function () {}
But really, you only need to worry about this if you're creating a mashup or library for others to use. On your own site YOU have control of what gets included in javascript.
Actually, for performance reasons, it may be better to keep it in one file; multiple requests actually can take up more bandwidth... but as separate files, you would need to order them in a particular order so that there is a logical sequence. Instead of having everything in a document.ready, have each script define a method, that the page will execute within its own document.ready handler, so that you can maintain that order.
Most likely the reason it's coming up undefined is because when you have separate ready calls, the scope of the code inside those calls is different.
I would reorganize my code. Any shared functions can be attached to the jQuery object directly, using $.extend. This is what we do for our application and it works well.
See this question. Hope it helps.
Everyfile shouldnt have a ready function. Only one file should have the ready function and that should be the last file.
"wrapped in a jquery ready function" is nothing else than binding stuff to the ready event that is fired when jQuery thinks the DOM is ready.
You should only bind methods that is depending on the DOM to the ready event. It doesnt matter how many binds you make, all of the methods will be executed in the binding order in the end.
Functions provide scope in JavaScript. Your code in the jquery.ready is an anonymous function, so it is unaware of the other scopes. remove the wrappings for those JavaScript functions and declare them as regular functions, a la
$(document).ready(function ()
{
functionFromFile1();
functionFromFile2();
};