I'm a novice at Javascript/Jquery programming, so an apology if this is a simple/silly question.
I am trying to use the jQuery .getScript() function to refresh part of an existing webpage. This webpage must be run on a local file system, and a large amount of the formatting is done using frames.
Right now, there’s three main frames- a sidebar which displays possible “scopes” to choose from, a main frame which displays the majority of the contents of the webpage, and a footer frame. The main entry into the page is in an index.html file, which loads a sidebar.html, main.html, and footer.html file into each of the respective frames.
In turn, the main.html has a number of javascript files which it loads, the main being a main.js, which contains numerous functions to format/process the contents for this main window. After loading this javascript file, main.html loads a few javascript files, which contain the data which is going to be displayed in the main frame. These files that are loaded have a fixed data structure, and are dependent on the functions that were loaded by the main.js file.
Loading the webpage works fine now, but when a user tries to switch to another “scope”, the whole webpage is reloaded to make the switch. The only difference in the webpage is the content in the main.js frame, loaded in by a different set of .js files.
Enough text, let’s look at some code.
When the webpage loads, I tried to add a simple call to the getScript function in a .js file at the index.html level which handles switching scopes. This file, newFile, has different data definitions than the previously loaded oldFile.js which was loaded in the main.html file.
$.getScript(/js/newFile.js);
However this doesn’t work, since newFile.js depends on a parseData() function which is in main.js.
If I open firebug up, parseData is not located in the dom tab, which I assume is related to some scoping issue with the main.html and main.js file existing in a different frame.
I tried to do some targeting to the correct “frame” but I don’t think I understand jQuery enough to know what is happening.
$(window.parent.frames[0]).getScript(/js/newFile.js);
Any suggestions?
If I were to type into firebug console “parseData” it can not find it: “ReferenceError: parseData is not defined”
However, if I type in window.parent.frames[1].parseData, it can find the function.
Sorry about all the rambling and poor understanding of javascript. Hopefully someone can provide some assistance!
Thanks
.getScript() executes the loaded script in the global context. I would assume that since your parseData() function is not available at global scope. You could try defining parseData globally by wrapping it in a jQuery.globalEval() call like so:
$.globalEval("
function parseData(){
alert('It works!');
}
");
I haven't tested but I have run into similar situations using the javascript setTimeout() function since it also executes globally.
Related
I have a project where I have three separate JavaScript files (example1.js, example2.js and example3.js lets call them) scripted into one html file (index.html). These three JS files between them are responsible for an API call and manipulating the result.
One of the JS files, example1.js refers to a global variable located in example2.js and as they were both loading into the same html document I thought the access to said variable wouldn't be an issue and it did indeed work perfectly fine until I added the files to my RoR app. Due to Rails I had to encase the JS/jQuery code inside of $document.ready(function(){}
(I should probably should do this as a matter of course anyway?).
The effect this has had is that I am now getting a 'variable not defined' error on the global variable referred to by example1.js that is located in example2.js, even though other code in the same file is working correctly.
I went back to my original JS files away from RoR incase it was a Rails issue. However, encasing the code in my original files with the jQuery document.ready function has the same effect outside of the Rails environment. Can someone explain why this is and a possible solution?
I completely overlooked the fact that document.ready is itself a function and therefore removed everything from the global scope into the function scope of document.ready.
Google Pagespeed said I should load my JS files asynchronously, but this has introduced a problem for many of my pages with code using libraries and plugins.
For example, I have the following code on one page:
$(document).ready(function () {
var hound = new Bloodhound({ .......
});
So when the page loads, I am creating a Twitter Bloodhound (goes with Typeahead) object. The problem is, if Bloodhound and Typeahead are loaded asynchronously, then an error is thrown:
Uncaught ReferenceError: Bloodhound is not defined
This is because those scripts haven't been loaded yet.
I came up with this solution:
$(document).ready(function () {
createBloodhound();
});
function createBloodhound() {
if (typeof Bloodhound != "undefined") { // if bloodhound JS has loaded
var hound = new Bloodhound({ .......
}
else {
setTimeout(function(){
createBloodhound();
}, 10);
}
}
Is this a good practice, or is there a better way?
NOTE: I realize there are libraries like RequireJS out there to handle dependencies when loading files, but I don't think this type of solution will not work in my case because I load the libraries asynchronously in a wrapper file (since they're required for every page). The example code here would not be on every page, but only on a specific page on my website.
The best approach is to use a callback mechanism, which you can react to, rather than using a polling mechanism. I used script.js, which is simple and yet functional, and offers the callback mechanism.
Without that, you could implement something yourself. Performance-wise though, utilizing callback are better.
Depending on the complexity of your site, different options might be best. If...
All of your javascript is in JS files
Your above-the-fold content looks identical before and after the JS is loaded (or close enough to identical that the flash of change when your JS does load wouldn't distract your users)
The total file size is small (or most of your JS is needed on pages everyone will visit every time they visit your site)
... then combine them into one file and just server that instead of all the individual ones. Then you don't have to worry about dependencies at all. Include that script file at the bottom of your body tag (no need for async or defer attributes, but you can use them if you want).
If some of your javascript is necessary to make your above-the-fold content look correct, do the same thing, except split your JS into two files. One file contains only what is necessary to make the above-the-fold content look correct, and the other file contains everything else. Include the first one in your head tag (possibly inlining it), and include the second one at the bottom of your body tag. If the second one depends on the first tag, do not use the async attribute, because it might get executed first.
If you have some large JS files that are only used on some pages, and those files depend on other JS files, stick your scripts at the bottom of your body tag and use the defer attribute.
If you have javascript mixed in with your HTML, you can use a callback mechanism (like script.js), or you can build up execution queues like Google Analytics does, which the external script knows to look for when it first loads.
I'm looking for some advice on the best way to hold my JavaScript (jQuery) functions.
I am developing in MVC/razor and therefore have a layout page. I include my jQuery library and an external JavaScript file in here so it's available in every single page.
This is working well, but I am now becoming very aware of the fact that I am adding almost 300 lines of JS to EVERY page, where maybe half of that is used in any one of these pages.
One function is not in the external file and instead sits inside the HTML because I need to use variables set in my razor code.
I have a couple of questions around this arrangement:
Is placing JS inside the HTML generally acceptable when variables set using razor are used? There does not appear to be a clean way of passing a variable into an external js file
Should I split my functions down in to individual JS files and just include what is needed for each page in the site?
If I were to split them into multiple files, how would that work with jQuery's (document).ready ? Do I need to use that if all the JavaScript I am including is to be used?
I'm sure this will more a matter of opinion than a black and white answer, but I want to consider all my options before moving on. Even though it works fine as is, I can't help but feel there is a better/cleaner way.
Remember once a user lands on your homepage and loads the javascript file it will be cached in their browser so subsequent pages will not download the Javascript again.
I would definitely keep the js separate, you could have a snippet on each page that initialise the JS that that particurlar view needs. Put something like the below in the views that need to run JS
$(document).ready(function() {
mysite.mypage();
});
Then the function mysite.mypage() can be defined in the external JS file.
300 lines isnt the end of the world, I would say its probably too early to be worryign about optimisation.
You could always look at minifying that JS file to decrease the size. A quick and easy way to do this is here:
http://www.minifyjavascript.com/
Have you ever heard of require.js? http://requirejs.org/ I find it really useful.
It's a module loader so you are able to split all of your JS code into individual files and load only the ones you need on each page.
I don't know about passing a variable to an external JS file, I don't think its possible / the 'right' way.
You can make each external JS file into a function that accepts and returns parameters. Then in the page you need to use it:
- include the file dependancy
- call the function
Thats what I do, seems like your 2nd suggestion.
for the $(document.ready) question its really up to you. You don't have to use it but its useful for some things , check out this overview:
http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
I have a single file, 'core.js', with a collection of my sites JavaScript. I like to combine my script this way so I can cut down on HTTP requests. My problem is, page specific code's, obviously, getting run on pages it needn't.
Without splitting 'core.js' into separate scripts, what's the best solution for ensuring my page specific code only gets run on the page it's supposed to be run on?
Many thanks!
The simplest way is to make everything in core.js be functions and then put one inline function call in each given page to call the code specific to that page. That makes core.js a resource and each page decides what functions in that resource to call.
I've also seen it done where you put a trigger class name on the body tag and then the code in core.js examines the classes on the body tag to decide what initialization code to run. This works best when you have a small number of types of pages and you want to run the same initialization code on all pages of the same type, but I don't think it's all that good if each page has different JS. In that case, I think it's better to use the first technique of let the page decide what JS initialization function to call.
What is the general developer opinion on including javascript code on the file instead of including it on the script tag.
So we all agree that jquery needs to be included with a script file, like below:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"
type="text/javascript"></script>
My question is, in order to get functions on a page that is not on all pages of a site. Do we include the functions like below in the same page or in a global include file like above called mysite.js.
$(document).ready(function(){
$(".clickme").click(function(event){
alert("Thanks for visiting!");
});
});
ok. So the question is: if the code above is going to be called in every class="clickme" on a specific pages, and you have the ability to call it either from an include separate file called mysite.js or in the content of the page. Which way will you go?
Arguments are:
If you include it on the page you will only call it from those specific pages that the js functionality is needed.
Or you include it as a file, which the browser cached, but then jquery will have to spend x ms to know that that function is not trigger on a page without "clickme" class in it.
EDIT 1:
Ok. One point that I want to make sure people address is what is the effect of having the document.ready function called things that does not exist in the page, will that trigger any type of delay on the browser? Is that a significant impact?
First of all - $("#clickme") will find the id="clickme" not class="clickme". You'd want $(".clickme") if you were looking for classes.
I (try to) never put any actual JavaScript code inside my XHTML documents, unless I'm working on testing something on a page quickly. I always link to an external JS file to load the functionality I want. Browsers without JS (like web crawlers) will not load these files, and it makes your code look much cleaner to the "view source".
If I need a bit of functionality only on one page - it sometimes gets its own include file. It all depends on how much functionality / slow selectors it uses. Just because you put your JS in an external JS file doesn't mean you need to include it on every page.
The main reason I use this practice - if I need to change some JavaScript code, it will all be in the same place, and change site wide.
As far as the question about performance goes- Some selectors take a lot of time, but most of them (especially those that deal with ID) are very quick. Searching for a selector that doesn't exist is a waste of time, but when you put that up against the wasted time of a second script HTTP request (which blocks the DOM from being ready btw), searching for an empty selector will generally win as being the lesser of the two evils. jQuery 1.3 Performace Notes and SlickSpeed will hopefully help you decide on how many MS you really are losing to searching for a class.
I tend to use an external file so if a change is needed it is done in one place for all pages, rather than x changes on x pages.
Also if you leave the project and someone else has to take over, it can be a massive pain to dig around the project trying to find some inline js.
My personal preference is
completely global functions, plugins and utilities - in a separate JavaScript file and referenced in each page (much like the jQuery file)
specific page functionality - in a separate JavaScript file and only referenced in the page it is needed for
Remember that you can also minify and gzip the files too.
I'm a firm believer of Unobtrusive JavaScript and therefore try to avoid having any JavaScript code in with the markup, even if the JavaScript is in it's own script block.
I agreed to never have code in your HTML page. In ASP.net I programmatically have added a check for each page to see if it has a same name javascript file.
Eg. MyPage.aspx will look for a MyPage.aspx.js
For my MVC master page I have this code to add a javascript link:
// Add Each page's javascript file
if (Page.ViewContext.View is WebFormView)
{
WebFormView view = Page.ViewContext.View as WebFormView;
string shortUrl = view.ViewPath + ".js";
if (File.Exists(Server.MapPath(shortUrl)))
{
_clientScriptIncludes["PageJavascript"] = Page.ResolveUrl(shortUrl);
}
}
This works well because:
It is automagically included in my files
The .js file lives alongside the page itself
Sorry if this doesn't apply to your language/coding style.