Moving JavaScript out of the Web Page

Finding Script Content To Be Moved

When you first write a new JavaScript the easiest way to set it up is to embed the JavaScript code directly into the web page so that everything is in the one place while you test it to get it working right. Similarly if you are inserting a pre written script into your web site the instructions may tell you to embed parts or all of the script into the web page itself.

This is okay for setting up the page and getting it to work properly in the first place but once your page is working the way that you want it you will be able to improve the page by extracting the JavaScript into an external file so that your page content in the HTML isn't so cluttered with non-content items such as JavaScript.

If you just copy and use JavaScripts written by other people then their instructions on how to add their script to your page may have resulted in your having one or more large sections of JavaScript actually embedded into your web page itself and their instructions don't tell you how you can move this code out of your page into a separate file and still have the JavaScript work. Don't worry though because regardless of what code the JavaScript you are using in your page you can easily move the JavaScript out of your page and set it up as a separate file (or files if you have more than one piece of JavaScript embedded in the page). The process for doing this is always the same and is best illustrated with an example.

Let's look at how a piece of JavaScript might look when embedded in your page. Your actual JavaScript code will be different from that shown in the following examples but the process is the same in every case.

Example One


<script type="text/javascript">
if (top.location != self.location)
top.location = self.location;
</script>

Example Two


<script type="text/javascript"><!--
if (top.location != self.location)
top.location = self.location;
// -->
</script>

Example Three


<script type="text/javascript">
/* <![CDATA[ */
if (top.location != self.location)
top.location = self.location;
/* ]]> */
</script>

Your embedded JavaScript should look something like one of the above three examples. Of course your actual JavaScript code will be different from that shown but the JavaScript will probably be embedded into the page using one of the above three methods. In some cases your code may use the outdated language="javascript" instead of type="text/javascript" in which case you may want to bring your code more up to date to start with by replacing the language attribute with the type one.

Before you can extract the JavaScript into its own file you first need to identify the code to be extracted. In all three of the above examples there are two lines of actual JavaScript code to be extracted. Your script will probably have a lot more lines but can be readily identified because it will occupy the same place within your page as the two lines of JavaScript that I have highlighted in the above three examples (all three of the examples contain the same two lines of JavaScript, it is just the container around them that is slightly different).

  1. The first thing you need to do to actually extract the JavaScript into a separate file is to open a plain text editor and access the content of your web page. You then need to locate the embedded JavaScript that will be surrounded by one of the variations of code shown in the above examples.
  2. Having located the JavaScript code you need to select it and copy it to your clipboard. With the above example the code to be selected is highlighted, you do not need to select the script tags or the optional comments that may appear around your JavaScript code.
  1. Open another copy of your plain text editor (or another tab if your editor supports opening more than one file at a time) and past the JavaScript content there.
  2. Select a descriptive filename to use for your new file and save the new content using that filename. With the example code the purpose of the script is to break out of frames so an appropriate name could be framebreak.js.
  3. So now we have the JavaScript in a separate file we return to the editor where we have the original page content to make the changes there to link to the external copy of the script.
  4. As we now have the script in a separate file we can remove everything between the script tags in our original content so that the </script&;script tag immediately follows the <script type="text/javascript"> tag.
  5. The final step is to add an extra attribute into the script tag identifying where it can find the external JavaScript. We do this using a src="filename" attribute. With our example script we would specify src="framebreak.js".
  1. The only complication to this is if we have decided to store the external JavaScripts in a separate folder from the web pages that use them. If you do this then you need to add the path from the web page folder to the JavaScript folder in front of the filename. For example if the JavaScripts are being stored in a js folder within the folder that holds our web pages we would need src="js/framebreak.js"

    So what does our code look like after we have separated the JavaScript out into a separate file. In the case of our example JavaScript (assuming that the JavaScript and HTML are in the same folder) our HTML in the web page now reads:

    
    <script type="text/javascript" src="framebreak.js">
    </script>
    
    

    We also have a separate file called framebreak.js that contains:

    
    if (top.location != self.location)
    top.location = self.location;
    
    

    Your filename and file content will be a lot different from that because you will have extracted whatever JavaScript was embedded in your web page and given the file a descriptive name based on what it does. The actual process of extracting it will be the same though regardless of what lines it contains.

    What about those other two lines in each of examples two and three? Well the purpose of those lines in example two is to hide the JavaScript from Netscape 1 and Internet Explorer 2, neither of which anyone uses any more and so those lines are not really needed in the first place. Placing the code in an external file hides the code from browsers that don't understand the script tag more effectively than surrounding it in an HTML comment anyway. The third example is used for XHTML pages to tell validators that the JavaScript should be treated as page content and not to validate it as HTML (if you are using an HTML doctype rather than an XHTML one then the validator already knows this and so those tags are not needed).

    With the JavaScript in a separate file there is no longer any JavaScript in the page to be skipped over by validators and so those lines are no longer needed.

    One of the most useful ways that JavaScript can be used to add functionality to a web page is to perform some sort of processing in response to an action by your visitor. The most common action that you want to respond to will be when that visitor clicks on something. The event handler that allows you to respond to visitors clicking on something is called onclick.

    When most people first think about adding an onclick event handler to their web page they immediately think of adding it to an <a> tag.

    This gives a piece of code that often looks like:

    
    <a href="#" onclick="dosomething(); return false;">
    
    

    This is the wrong way to use onclick unless you have an actual meaningful address in the href attribute so that those without JavaScript will be transferred somewhere when they click on the link. A lot of people also leave out the "return false" from this code and then wonder why the top of the current page always gets loaded after the script has run (which is what the href="#" is telling the page to do unless false is returned from all the event handlers. Of course if you have something meaningful as the destination of the link then you may want to go there after running the onclick code and then you will not need the "return false".

    What many people do not realise is that the onclick event handler can be added to any HTML tag in the web page in order to interact when your visitor clicks on that content.

    So if you want something to run when people click on an image you can use:

    
    <img src="myimg.gif" onclick="dosomething()">
    
    

    If you want to run something when people click on some text you can use:

    
    <span onclick="dosomething()">some text</span>
    
    

    Of course these don't give the automatic visual clue that there will be a response if your visitor clicks on them the way that a link does but you can add that visual clue easily enough yourself by styling the image or span appropriately.

    The other thing to note about these ways of attaching the onclick event handler is that they do not require the "return false" because there is no default action that will happen when the element is clicked on that needs to be disabled.

    These ways of attaching the onclick are a big improvement on the poor method that many people use but it is still a long way from being the best way of coding it. One problem with adding onclick using any of the above methods is that it is still mixing your JavaScript in with your HTML. onclick is not an HTML attribute, it is a JavaScript event handler. As such to separate our JavaScript from our HTML to make the page easier to maintain we need to get that onclick reference out of the HTML file into a separate JavaScript file where it belongs.

    The easiest way to do this is to replace the onclick in the HTML with an id that will make it easy to attach the event handler to the appropriate spot in the HTML. So our HTML might now contain one of these statements:

    
    < img src="myimg.gif" id="img1">
    <span id="sp1">some text</span>
    
    

    We can then code the JavaScript in a separate JavaScript file that is either linked into the bottom of the body of the page or which is in the head of the page and where our code is inside a function that is itself called after the page finishes loading.

    Our JavaScript to attach the event handlers now looks like this:

    
    document.getElementById('img1').onclick = dosomething;
    document.getElementById('sp1').onclick = dosomething;
    
    

    One thing to note. You will notice that I have always written onclick entirely in lowercase. When coding the statement in their HTML you will see some people write it as onClick. This is wrong as the JavaScript event handlers names are all lowercase and there is no such handler as onClick. You can get away with it when you include the JavaScript inside your HTML tag directly since HTML is not case sensitive and the browser will map it across to the correct name for you. You can't get away with wrong capitalisation in your JavaScript itself since the JavaScript is case sensitive and there is no such thing in JavaScript as onClick.

    This code is a huge improvement over the prior versions because we are now both attaching the event to the correct element within our HTML and we have the JavaScript completely separate from the HTML. We can improve on this even further though.

    The one problem that is remaining is that we can only attach one onclick event handler to a specific element. Should we at any time need to attach a different onclick event handler to the same element then the previously attached processing will no longer be attached to that element. When you are adding a variety of different scripts to your web page for different purposes there is at least a possibility that two or more of them may want to provide some processing to be performed when the same element is clicked on.

    The messy solution to this problem is to identify where this situation arises and to combine the processing that needs to be called together into a function that performs all of the processing.

    While clashes like this are less common with onclick than they are with onload, having to identify the clashes in advance and combine them together is not the ideal solution. It is not a solution at all when the actual processing that needs to be attached to the element changes over time so that sometimes there is one thing to do, sometimes another, and sometimes both.

    The best solution is to stop using an event handler completely and to instead use a JavaScript event listener (along with the corresponding attachEvent for Jscript- since this is one of those situations where JavaScript and Jscript differ). We can do this most easily by first creating an addEvent function that will add either an event listener or attachevent depending on which of the two that the language being run supports;

    
    function addEvent(el, eType, fn, uC) {
    if (el.addEventListener) {
    el.addEventListener(eType, fn, uC);
    return true;
    } else if (el.attachEvent) {
    return el.attachEvent('on' + eType, fn);
    }
     }
    
    

    We can now attach the processing that we want to have happen when our element is clicked on using:

    
    addEvent(
    document.getElementById('spn1'),
    'click',dosomething,false);
    
    

    Using this method of attaching the code to be processed when an element is clicked on means that making another addEvent call to add another function to be run when a specific element is clicked on will not replace the prior processing with the new processing but will instead allow both of the functions to be run. We have no need to know when calling an addEvent whether or not we already have a function attached to the element to run when it is clicked on, the new function will be run along with and functions that were previously attached.

    Should we need the ability to remove functions from what gets run when an element is clicked on then we could create a corresponding deleteEvent function that calls the appropriate function for removing an event listener or attached event.

    The one disadvantage of this last way of attaching the processing is that really old browsers do not support these relatively new ways of attaching event processing to a web page. There should be few enough people using such antiquated browsers by now to disregard them in what J(ava)Script we write apart from writing our code in such a way that it doesn't cause huge numbers of error messages. The above function is written so as to do nothing if neither of the ways it uses is supported.

    Most of these really old browsers do not support the getElementById method of referencing HTML either and so a simple if (!document.getElementById) return false; at the top of any of your functions which do such calls would also be appropriate. Of course many people writing JavaScript are not so considerate of those still using antique browsers and so those users must be getting used to seeing JavaScript errors on almost every web page they visit by now.

    Which of these different ways do you use to attach processing into your page to be run when your visitors click on something? If the way you do it is nearer to the examples at the top of the page than to those examples at the bottom of the page then perhaps it is time you thought about improving the way you write your onclick processing to use one of the better methods presented lower down on the page.

    Looking at the code for the cross browser event listener you will notice that there is a fourth parameter which I called uC, the use of which isn't obvious from the prior description.

    Browsers have two different orders in which they can process events when the event is triggered. They can work from the outside inwards from the <body> tag in towards the tag that triggered the event or they can work from the inside out starting at the most specific tag.

    These two are called capture and bubble respectively and most browsers allow you to choose which order multiple processing should be run in by setting this extra parameter.

    • uC = true to process during the capture phase
    • uC = false to process during the bubble phase.

    So where there are several other tags wrapped around the one that the event was triggered on the capture phase runs first starting with the outermost tag and moving in toward the one that triggered the event and then once the tag the event was attached to has been processed the bubble phase reverses the process and goes back out again.

    Internet Explorer and traditional event handlers always process the bubble phase and never the capture phase and so always start at the most specific tag and work outwards.

    So with a event handlers:

    
    <div onclick="alert('a')><div onclick="alert('b')">xx</div></div>
    
    

    clicking on the xx would bubble out triggering the alert('b') first and the alert('a') second.

    If those alerts were attached using event listeners with uC true then all modern browsers except Internet Explorer would process the alert('a') first and then the alert('b').