Context Driven JavaScript Programming

First let me say that while I will be focusing on JQuery for the framework of choice, this can really be accomplished with most of the frameworks available.

The idea of context driven JavaScript programming is actually use JavaScript to do what you are intending and make things easier.  Many programmers often assume that JavaScript can do very little and thus create tremendous tasks for themselves when in fact the code is very simple if they would simply employ the concept of context and utilize what JavaScript is giving them.  Lets look at an example of some bad JavaScript:

  1: var selectBox = null;
  2: window.onload = LoadingFunction;
  4: function LoadingFunction() {
  5:     selectBox = document.getElementById('selectGender');
  6:     selectBox.onchange = HandleChange;
  7: }
 10: function HandleChange() {
 11:     var value = selectBox.options[selectBox.selectedIndex].value;
 12:     alert(value);
 13: }

First thing I want to point out is that some of you may say, well why do I need to define my handlers in JavaScript, I can just define them in the markup and pass what I need. I would say, yes that does work, but its a mixing of your presentation and interaction layers and will get you into trouble as you work on larger more complex JavaScript driven processes.  But lets turn our attention to this code.  Seems alright, but lets rewrite it using context:

   1:  window.onload = function() {
   2:      document.getElementById('selectGender').onchange = function() {
   3:          alert(this.options[this.selectedIndex].value);
   4:      }
   5:  }

.csharpcode, .csharpcode pre
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
background-color: #f4f4f4;
width: 100%;
margin: 0em;
.csharpcode .lnum { color: #606060; }

This is quite a few lines less then what we were using.  You see the use of the word this within an anonymous function assigned as event handler gives you a reference to the object firing the event, this allows you to easily use the same event handler over and over.  Using anonymous functions in this way also allows you to utilize scope convergence and include scope outside of the function, with static functions from the first example you would not have this ability.

  1: window.onload = function() {
  2:     var name = prompt("What is your name?");
  3:     document.getElementById('selectGender').onchange = function() {
  4:         alert(name + " is " + this.options[this.selectedIndex].value);
  5:     }
  6: }

Notice how name is declared outside the anonymous function but used inside without anything special. If you were to do this with the first sample of code you would need to make name a global variable or find a way to pass it to the function, using context you can have it passed automatically.  Now keep in mind this is a very simple example.  One of the places where I use this principle heavily and it shows its worth is client side binding.

The scope of these functions is “saved” to the runtime of JavaScript and thus can be referenced later on when an instance of the event is called.  I invite you to read more about my experiments with JQuery as this comes in huge when we start talking about data driven programming as it eliminates the need to store lots of data in hidden fields for client side operations.

As our final step with this code, we will introduce JQuery and see how it simplifies this code:

  1: $(document).ready(function() {
  2:     var name = prompt("What is your name?", "Fred");
  3:     $("select").change(function() {
  4:         alert(name + " is " + $(this).val());
  5:     });
  6: });

As you can see, the code is not that different from the previous example, but I do want to point out a few things.  First is $(“select”); in this example we only have one so this query will return to us just that one instance and bind the event handler to the change event.  However, if we had more then one, then it would do this for each one – this is one of the things about JQuery that make it so great, being able to apple context specific event handlers en masse, this way. You also notice the simplified syntax for getting the value of the select box using the val() function. Finally the one weakness with the second example of code is the lack of graceful degradation.  In the case of JQuery, if the select box were somehow removed without removing the JavaScript, the page would still load error free, not the case with the JQuery-less code, thus you would need to employ a check to make sure you actually have an object to bind the event to, for example:

  1: window.onload = function() {
  2:     var name = prompt("What is your name?");
  3:     var elem = document.getElementById('selectGender');
  4:     if (elem != null) {
  5:         elem.onchange = function() {
  6:             alert(name + " is " + this.options[this.selectedIndex].value);
  7:         }
  8:     }
  9: }

Context driven programming has many advantages, but yet few use it heavily or near the level appropriate, why? Perhaps the biggest reason is laziness; both in desiring to understand and have the will to do it right, rather then quick and dirty. In the same way that it takes discipline to separate the layers of our web app and ensure that no SQL strings are ever found in a code-behind, so to do programming unobtrusive JavaScript.  Truthfully, unobtrusive is very difficult without a framework, as you see in the code above for the final example, but frameworks such as JQuery render this point moot and really shows the laziness of the person programming or perhaps their stubbornness with changing the way they program.

Additionally, most developers seem to scoff at the idea of a user browsing the site without JavaScript and in some cases its worked into the project contract that the is assumed to have JavaScript.  I find this silly, when really a simple toggle box that shows if JavaScript is not enabled performs the tasks quite admirably of steering off users who don’t have JavaScript.  This is certainly better to the alternative.

Finally, most designers, if you ask them, are driven nuts by having their HTML littered with event handlers.  They do not belong here, they are not part of the presentation, they are part of the interaction, like entity objects and data access layers, they should be separated into their own layers so you can emphasis code reuse.

The last point I have heard made against this style of programming is maintainability. Some appear to feel that wiring up your events like I have shown above limits your ability to change if element names were to change.  There is certainly some truth to this, but context driven programming counters this with its emphasis on The Principle of Localization.  When you are coding your handlers correctly the brunt of the code that could change is concentrated in a single block, thus negating the need to scroll around making sure you found all the references.  Furthermore a framework like JQuery is very flexible in how it can query for elements, and understanding the ways you can do this is essential.  Simply knowing the basic selectors is not enough; in fact I have observed that if you start to break away from attaching to simply ids the code becomes more abstract and easier to change.  The downside is that because JQuery is designed to degrade gracefully, you will not see any errors when you are running, so your unit tests are not properly designed you may miss a bug.

The final thing I would like to say is that JQuery is and unobtrusive JavaScript are designed to work no matter how your elements are arranged or how many there are.  I have seen cases where programmers try interesting methods to mask the elements being passed, its a interesting method because it tends to result in ugly code that does not operate using context, all because they fear an element name changing.  Such an approach is very Web 1.0ish and quickly shows its limits when you start doing any kind of client side binding, which is very common in Web 2.0 apps.

One of the most important concepts Web 2.0 is bring us is that there is a dire need to understand how to architect our JavaScript in the application.  Most good developers understand the importance of properly architecting server side code (think of the number of patterns that exist), but there is a lack of understanding for architecting client side code. Understanding what you can make a function and what you should not will be critical along with understanding core JavaScript concepts like prototyping and JQuery concepts like extending.

To conclude, as the web continues to move forward in terms of the expectation for web site interaction JavaScript is becoming the front line fighter in creating the memorable experience people want.  The age of static JavaScript programming is coming to an end and is being replaced by context driven programming where developers leverage what the language gives them to make their code cleaner and more coherent. Though certain concerns exist about this new methodology most are simply borne from either worrying too much about the odd case, or a lack of desire to change on the part of the programming. With a framework like JQuery programming your JavaScript to be unobtrusive is easy and quick, further understanding how to leverage context in your code gives you an easy way to reference the elements you care about without tying your interaction to your design.  This makes changes easier and makes your code better and easier to understand for the next person.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s