Chapter 40. Separating JavaScript and HTML

Web applications are naturally separated into different layers. The HTML layer is responsible for getting data to the user, the CSS layer is responsible for the visual representation of that data, and JavaScript adds behavior to the page. Despite this separation, developers have a tendency to tie HTML, CSS, and JavaScript together by using inline style sheets or scripts, as well as by using the style and event handler attributes (such as onclick).

Proof of this is found in this book. In many examples you'll find the use of inline scripts or event handler attributes. It makes explanations and demonstrations easier while at the same time making maintenance a headache. The more tightly you integrate multiple layers, the more work you face when making changes down the road.

Using inline scripts and event handler attributes is technically correct. After all, the examples in this book use them, but their use made the examples harder to maintain and, in the case of errors, fix. Consider the following code as an example:

<form name="theForm" onsubmit="submitFom(event);" />

<script type="text/javascript">
function submitForm(event) {
    alert("Submitting!");
}
</script>

There is an error in this code. But where? Is it in the <form/> element's onsubmit attribute or in the JavaScript code? You have a 50 percent chance of picking the correct spot to start debugging, and if you pick wrong you've wasted time. The actual error is in the onsubmit event handler: It calls submitFom(), not submitForm(). Now, this is a very simple example, so imagine having to debug several HTML attributes and inline scripts on multiple pages. That's a daunting task.

This example also brings up another way in which an error might occur: The form could be submitted before the submitForm() function is available to the browser. In other words, the submitForm() function isn't loaded by the browser when the user submits the form. It's one of those errors that you personally may not experience when developing your application, but that users on varying connections, especially slow ones, could experience.

Decoupling your JavaScript and HTML is one of the tenants of progressive enhancement, a Web development philosophy that champions accessibility. The idea behind progressive enhancement is to create a bare-bones document that works in all browsers (no CSS or JavaScript whatsoever). Then the developer adds enhancements to the page via external style sheets or JavaScript. Progressive enhancement enables users with the latest browsers to experience the full-feature page; whereas, users with JavaScript-disabled browsers can still use the page's basic functionality without having to download the unnecessary JavaScript files.

The previous form submittal example is a perfect illustration of how progressive enhancement can improve a user's experience. Examine the following HTML:

<form name="theForm" onsubmit="submitForm(event);" />

<script type="text/javascript">
function submitForm(event) {
    alert("Submitting!");
}
</script>

Browsers with JavaScript disabled still have to download the inline JavaScript because it's part of the HTML document. Compare that code with the following HTML:

<form name="theForm" />

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

The JavaScript code within formStuff.js contains all the code necessary to provide enhanced features and usability for users of modern web browsers. For users of browsers with JavaScript enabled, the external file is downloaded. Users of browsers with JavaScript disabled don't need the file; the browser ignores the external file and doesn't download it. So by following the progressive enhancement philosophy (and thus separating your JavaScript and HTML), you provide features for users that want them while improving performance for users that don't.

Decoupling HTML and JavaScript means that JavaScript files are served separately from HTML documents. This gives you the ability to compress JavaScript files with gzip to make them smaller, serve them as cacheable so they only have to be downloaded once, and minify them, or remove unnecessary characters, using various tools like Yahoo!'s UI Compressor (http://developer.yahoo.com/yui/compressor/) or Douglas Crockford's JSMIN (http://crockford.com/javascript/jsmin).

So how can you separate your JavaScript and HTML? The first step is to remove all inline JavaScript and put it in external files. Second, remove all event handler attributes from your HTML elements, and finally, wire up events in your JavaScript.

TRY IT

In this lesson, you learn how to separate your JavaScript from HTML to avoid errors and make your application easier to maintain and debug.

Lesson Requirements

For this lesson, you need a text editor; any plain text editor will do. For Microsoft Windows users, Notepad is available by default on your system or you can download Microsoft's Visual Web Developer Express (www.microsoft.com/express/web/) or Web Matrix (www.asp.net/webmatrix/), both of which are free. Mac OS X users can use TextMate, which comes as part of OS X, or download a trial of Coda (www.panic.com/coda/). Linux users can use the built-in VIM.

You also need a modern web browser. Choose any of the following:

  • Internet Explorer 8+

  • Google Chrome

  • Firefox 3.5+

  • Apple Safari 4+

  • Opera 10+

Additionally, you need a webserver installed with PHP support. Refer to Lesson 31 on the DVD for installation instructions.

This lesson modifies Lesson 35's JSON example, so you need a directory called Lesson40 in your webserver's root directory, containing the eventUtility.js, ajaxUtility.js, car_dealership.php, and the json2.js files used in Lesson 35. You can also copy lesson35_example01.htm and paste it into the lesson40 folder. Just remember to rename it to lesson40_example01.htm.

Step-by-Step

  1. If you didn't copy lesson35_example01.htm, open your text editor and type the following:

    <html>
    <head>
        <title>Lesson 40: Example 01</title>
    </head>
    <body>
    <div id="divResults">
        <div id="divSearchMessage"></div>
        <div id="divSearchResults"></div>
    </div>
    <form name="theForm" method="post" action="car_dealership.php"
        onsubmit="submitForm(event);">
        <p>
            Make: <input type="text" name="txtMake" value="" />
        </p>
        <p>
            Model: <input type="text" name="txtModel" value="" />
        </p>
        <p>
            Year: <input type="text" name="txtYear" value="" />
        </p>
        <p>
            <input type="submit" name="btnSubmit" value="Submit" />
    </p>
    </form>
    <script type="text/javascript" src="eventutility.js"></script>
    <script type="text/javascript" src="ajaxUtility.js"></script>
    <script type="text/javascript" src="json2.js"></script>
    <script type="text/javascript">
    function submitForm(event) {
        var data = ajaxUtility.getRequestBody(document.theForm);
    
        ajaxUtility.makeGetRequest("car_dealership.php?" + data, processResponse);
    
        eventUtility.preventDefault(event);
    }
    
    function getCarString(carObj) {
        return [carObj.year, carObj.make, carObj.model].join(" ");
    }
    
    function processResponse(data) {
        var result = JSON.parse(data),
        var messageDiv = document.getElementById("divSearchMessage");
        var resultsDiv = document.getElementById("divSearchResults");
        var message = "";
        var results = [];
        var length = result.results.length;
        var carStr = getCarString(result.searchedCar);
    
        if (result.isFound) {
            message = "We found " + length + " matches for " + carStr;
        } else {
            message = "We could not find " + carStr + ". You might like: ";
    
            for (var i = 0; i < length; i++) {
                results.push(getCarString(result.results[i]));
            }
    
            resultsDiv.innerHTML = results.join("<br/>");
        }
    
        messageDiv.innerHTML = message;
    }
    </script>
    </body>
    </html>

    Save it as lesson40_example01.htm.

  2. Copy the inline JavaScript code and paste it into a new text file. Save this new file as lesson40_example01.js. Be sure to save it in the lesson40 directory.

  3. Now remove the inline code from your HTML file and reference the new lesson40_example01.js file as shown in the following HTML:

    <html>
    <head>
    <title>Lesson 40: Example 01</title>
    </head>
    <body>
    <div id="divResults">
        <div id="divSearchMessage"></div>
        <div id="divSearchResults"></div>
    </div>
    <form name="theForm" method="post" action="car_dealership.php"
        onsubmit="submitForm(event);">
        <p>
            Make: <input type="text" name="txtMake" value="" />
        </p>
        <p>
            Model: <input type="text" name="txtModel" value="" />
        </p>
        <p>
            Year: <input type="text" name="txtYear" value="" />
        </p>
        <p>
            <input type="submit" name="btnSubmit" value="Submit" />
        </p>
    </form>
    <script type="text/javascript" src="eventutility.js"></script>
    <script type="text/javascript" src="ajaxUtility.js"></script>
    <script type="text/javascript" src="json2.js"></script>
    <script type="text/javascript" src="lesson40_example01.js"></script>
    </body>
    </html>

    Doesn't that look cleaner?

  4. Remove the onsubmit attribute from the <form/> element. The new code should look like the following:

    <html>
    <head>
        <title>Lesson 40: Example 01</title>
    </head>
    <body>
    <div id="divResults">
        <div id="divSearchMessage"></div>
        <div id="divSearchResults"></div>
    </div>
    <form name="theForm" method="post" action="car_dealership.php">
        <p>
            Make: <input type="text" name="txtMake" value="" />
        </p>
        <p>
            Model: <input type="text" name="txtModel" value="" />
        </p>
        <p>
            Year: <input type="text" name="txtYear" value="" />
        </p>
        <p>
            <input type="submit" name="btnSubmit" value="Submit" />
    </p>
    </form>
    <script type="text/javascript" src="eventutility.js"></script>
    <script type="text/javascript" src="ajaxUtility.js"></script>
    <script type="text/javascript" src="json2.js"></script>
    <script type="text/javascript" src="lesson40_example01.js"></script>
    </body>
    </html>

    JavaScript code is now completely absent from your HTML. It is good.

  5. All you need to do now is handle the <form/>'s submit event. In lesson40_example01.js, add the following line at the end of the file:

    eventUtility.addEvent(document.forms[0], "submit", submitForm);

    This code uses the eventUtility object to add a submit event handler to the form.

Now your JavaScript is completely separate from your HTML. Any change you make to the JavaScript code is done without your touching any of the HTML. Also, any JavaScript error that might occur can originate only from the JavaScript contained in the external files. There's no more guessing involved in determining if the error originated from HTML or JavaScript.

Note

Even by completely separating HTML and JavaScript, the form in this can still be submitted before the submitForm(), or the code that assigns it to handle the submit event is loaded by the browser. Premature form submission cannot be prevented.

You'll continue this best practices study in Lesson 41 when you learn how to decouple JavaScript and CSS.

To get the sample code files, download Lesson 32 from the book's website at www.wrox.com.

Note

Please select Lesson 40 on the DVD to view the video that accompanies this lesson.

Step-by-Step
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.82.21