Free Saeed Malekpour, Website Developer

Contact Me

@zoltandulac

Most Popular Posts

  • Cross Browser CSS Transforms – even in IE
  • How to Detect Font-Smoothing Using JavaScript
  • @font-face in Depth
  • Cross Browser HTML5 Drag and Drop
  • Installing Cygwin and FontForge for Windows
  • Cross Browser HTML5 Progress Bars In Depth
  • Creating Cross Browser HTML5 Forms Now, Using modernizr, webforms2 and html5Forms
  • Categories

    Configuring JavaScript Applications With XML

    October 27th, 2009 by admin · No Comments

    Remixed from an image from the Open Clip Art Library

    I have been hacking JavaScript for close to 12 years now, and love it.  But just like anyone you have been enamored with for a long time, there are bound to be things that drive you crazy about the object of your affection.  Sure, your feelings are stronger than when you first met, but sometimes, after you’ve had an a disagreement after a late night of coding, you catch yourself thinking “why in the world does she do things that way!?! Ridiculous!  She is driving me crazy with her inflexibility!”  You then calm down, and realize that despite her flaws, she is still the exciting, cool and can’t-live-without-her girl she was when you first met her – maybe even more so.

    Okay, I don’t mean to equate JavaScript with my wife (that may result with me sleeping on the couch tonight).  But sometimes the way JavaScript does things is pretty silly.  You’d figure after all these years, some of these things would have changed, but they haven’t.

    Long Strings in JavaScript

    Take for example the way that JavaScript likes to handle long, multi-line strings:

    var html = "<thead><tr><th>Name</th><th>Address</th><th>City</th>" +
    "<th>Province</th><th>Postal Code</th><th>Telephone</th></tr></thead>";

    Concatenating strings is a pretty expensive operation, both in memory and processing time, and using concatenation  it to describe a constant string doesn’t make too much sense. But putting this string on one line would make the code quite unwieldy to read.  Plus it looks ugly.  I may be a slob in real life (my coworkers and my family could go on for hours about that one) , but I love my code neat.

    Hard-Coding Values into Scripts

    Another problem I have with this method of defining strings is that we are hard-coding text into the script. This is not a problem unique to JavaScript by any means, but this breaks the Structure/View/Behaviour separation model that I like to follow when I code a web application.  Furthermore, if we had two pages with the same content but written in different languages (like in Canada, where a lot of sites are in English and French) we either have to have two versions of our script, or have the script broken into two parts: one with all the general code in it and one containing the language specific code.    While the latter is the more desirable of the two, it doesn’t lend itself to integrate well with some server-side web application frameworks like Java Struts.

    Furthermore, I hate hard-coding any type of value (strings, integers, and any type of objects) directly into my scripts.  Scripts should be flexible enough to be used in any type of situation – your table pagination script may work well with having ten rows on the page at the time in one situation, but in another, you may want 15 or 20.

    One comment I hear all the time is “Why not use JSON”? JSON is great, but because it is based on JavaScript, it is still gets ugly when manipulating long strings.

    Enter config.js to the Rescue

    In fact, it was Struts that inspired me to write the config.js JavaScript library.  If you aren’t familiar with it, Struts is a Java Framework that allows developers to configure their server-side web applications easily with a set of XML files.  It seemed natural to do the same in JavaScript, given all the DOM and XML processing routines that it has at its disposal, so I built config.js to do this task.  With this library, JavaScript developers can configure their own scripts using a block of XML.  This block of XML can be either embedded inside the HTML document (via an HTML comment) or in a separate XML file of its own.  And this configuration block can contain any number of strings, numbers, arrays or objects that a developer would need to get the job done.

    For example, let’s say you had a JavaScript function that looked like this:

    function submitFormEvent(e){
      var amount = document.getElementById("amount").innerHTML;
      var creditCardType = document.getElementById("ccType").value;
      var month = document.getElementById("month").value;
    
      var configString = "Submitting this order will charge " + amount +
        " to your " + creditCardType +
        " and will be received on your " + month +
        " credit card bill.  Are you sure you want to do" +
        " this?");
    
      if (window.confirm(configString)) {
        window.location = "http://www.mycompany.com/myApp/chargeMe.do";
      }
      return;
    }

    As you can see, the English literals are hard-coded in the script and there is a lot of string concatenation going on.  One could refactor the script to use config.js to fix these issues in four simple steps:

    1. Include the EventHelpers.js and config.js scripts in the <head> of your document (EventHelpers.js is included with the config.js archive):
      <script type=”text/javascript” src=”/path/to/EventHelpers.js”></script>
      <script type=”text/javascript” src=”/path/to/config.js”></script>
    2. Insert an XML block that contains the hard-coded strings in an HTML tag with an id of config:
      <div id="config">
      <!--
      <config>
        <myApp>
         <confirmCharge>
            <text>
      Submitting this order will charge @amount@  to your
      @creditCardType@ and will be received on your @month@
      credit card bill.  Are you sure you want to do this?
            </text>
            <url>http://www.mycompany.com/myApp/confirm.do</url>
         </confirmCharge>
        </myApp>
      </config>
       -->
      </div>
    3. Refactor you code to use config.js routines:
      function submitFormEvent(e){
            var amount = document.getElementById("amount").innerHTML;
            var creditCardType = document.getElementById("ccType").value;
            var month = document.getElementById("month").value;
      
            var configString = config.getScriptedValue(
                "myApp.confirmCharge.text",
                {
                  amount: amount,
                  creditCardType: creditCardType,
                  month: month
                });
      
            if (window.confirm(configString)) {
                window.location = config.getValue("myApp.confirmCharge.url");
            }
      
            return;
      }
    4. Replace any window.onload calls in your code with config.addLoadEvent() to ensure that any code that relies on config.js is initialized after the XML block is loaded into memory:
      config.addLoadEvent(exampleConfigForm.init);

    That’s it!  If you need to internationalize your application, use whatever internationalization framework your server side code uses – it should integrate well with config.js.  I use it with Java Struts all the time.

    See an example of the above code in action

    Use config.js in All Your Scripts

    Have more than one script on a page that you want to use config.js with?  No problem!  Add another block of XML inside the <config> node right after your other scripts config information:

    <div id=”config”>
    <!--
    <config>
      <myApp>
       <confirmCharge>
          <text>
    Submitting this order will charge @amount@  to your
    @creditCardType@ and will be received on your @month@
    credit card bill.  Are you sure you want to do this?
          </text>
          <url>http://www.mycompany.com/myApp/confirm.do</url>
       </confirmCharge>
      </myApp>
    
    <calendarWidget>
      <instructions>Enter in a valid date after @dateBegin@</instructions>
      <errors>
        <notValid>The date you entered is not valid</notValid>
        <holiday>
    Sorry, @date@ is a holiday and we won't be open
    at that time.  Please try again.
        </holiday>
      </errors>
    </calendarWidget>
    
    </config>
    -->
    </div>

    Now, all your configuration information for all your scripts can be in one place.  Programmers can now develop the code with place holders for the text, and not worry about accidentally messing up the code when marketing or customer service wants to make some textual changes.

    config.js can also handle HTML

    You can even insert full HTML inside the configuration XML block using a CDATA node:

    <config>
    <myApp>
      <browserWarning><![CDATA[
        <div class=”warning”>
        As of @date@ we will <strong>not</strong> be supporting Internet
        Explore 6 or lower.  Please <a href=”/howToUpgradeIE.html">upgrade your
        installation of Internet Explorer</a>, or install the latest version of one
        <a href=”/otherChoices.html”>the many alternative browsers available</a>.
        </div>
      ]]></browserWarning>
      </myApp>
    </config>

    This makes using an HTML node’s .innerHTML property even more fun! You longer do you have to hard-code long chunks of HTML inside your scripts. Try that with JSON!

    Framework Independent

    Config.js is not part of a JavaScript framework – you can use this library whether you use prototype, mootools, Dojo, jQuery or anything else that may come along. Please feel free to make improvements and changes on it – if you submit the changes back to me, I’ll incorporate them into the next official release.

    More Information

    There is way more to config.js than is explained here. Complete documentation for the library can be found here:
    config.js manual page

    Download

    You can get full source here:

    config.js v.2.0 and example code (zip format)

    Tags: JavaScript · XML

    0 responses so far ↓
    Give Feedback

    Don't be shy! Give feedback and join the discussion.

    Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.

    An orange star denotes a required field.