Troubleshooting Javascript: humble homage to WAT

Everyone who ever had the chance too see @garybernhardt‘s WAT presentation is secretly dreaming about emulating him some day… and luckily for all of us JavaScript provides us with plenty of opportunities to fulfil our wishes (BTW, don’t waste your time reading this article, you better waste your time watching WAT presentation)

JavaScript is not funny

Since early this year I’ve been heavily involved in a JavaScript project, and the fact is that there’s a lot of confusion about how JavaScript passes variables around (the so called pass-by-value / pass-by-reference debate), and if you add to the combo the intricacies of prototype inheritance, evaluations contexts and several other quirks, you’ll realize how easy is to shoot yourself in the foot working with JavaScript.

dont-shoot-yourself-in-the-foot

So, after shooting myself in both feet, and also blowing away my head a couple of times, I decided to try to shred some light on this subject.

In order to do so I’ll present the following articles

  • I – Preparing the ambush

  • I present a very basic Backbone view that allows us to render a group of radio button options. Then I add a method to dynamically add new radio buttons, and show the problems that might arise.

  • II – Forensic report

  • I scrutinize the former example to find out what went wrong and better identify our main suspects. Here I prepare some minimal js examples to test at the browser js console.

  • III – To reference or not to reference, that is the question

  • In this article I tackle the problem of JavaScript’s variable evaluation strategy, the good old by-value / by-reference / by-sharing debate.

  • IV – Class struggles

  • In the fourth article I talk about prototypical inheritance and the subtle ways in which things can go wrong

  • V – You start me on – a sane pattern for initializing objects

  • Finnally I try to come out with a sane pattern for setting the initial values of an object from a constructor, avoiding the pitfalls that we saw in the previous articles.

  • VI – Conclusions

  • Hopefully we shall end this journey with a better knowledge of JavaScript’s minefield and a couple of useful new tricks.

In the process I’ll try to introduce the following tools that I find indispensable to find our way around JavaScript quirks:

  • Stack Overflow – how could we survive without it?
  • Firefox and Chrome JavaScript console – best js programmer’s friend, no doubt about it
  • jsFiddle – To quickly show the world how JavaScript is making you suffer

Also Wikipedia proved quite useful for a deeper understanding of certain theoretical issues.

So without further ado let’s start with the first part of this series.

Scene one: preparing the ambush

We will start by implementing a very basic Backbone view which will allow us to display some radio buttons. We will specify the title of the radio button, the value of the currently selected one, and an object with all the key/text values.

To test it, we will just create two groups of radio buttons, one to let the user choose it’s gender and another to choose it’s age.

This is the html with the place holder divs for the radio buttons and backbone’s dependencies:

<html>

  <body>

    <h1>Javascript shootout</h1>

    <div id='genderRadio'></div><br />
    <div id='ageRadio'></div><br />

  </body>
  <script src='//cdn.jsdelivr.net/jquery/2.0.2/jquery.min.js'></script>
  <script src='//cdn.jsdelivr.net/underscorejs/1.4.4/underscore-min.js'></script>
  <script src='//cdn.jsdelivr.net/backbonejs/1.0.0/backbone-min.js'></script>
</html>

This is the template we’ll use to cycle thru the radios object properties and display each radio input:

<script type='text/template' id='radioTemplate'>
<label><%= title %></label><br />
<% _.each(radios, function(text, key) { %>
  <input type="radio" value="<%= key %>"<%= value === key ? ' checked' : '' %>><%= text %><br />
<% }); %>
</script>

Note that we are using the underscore’s micro-templating system. We are also using the _.each method from underscore. If you’re planning to spend more than a few hours programming in JavasScript, you owe to yourself to have a look at this library.

When the dom is ready we’ll define our RadioButtonView and we’ll instantiate two radio buttons groups, one with ages and another with genders.

This is the RadioButtonView

  var RadioButtonView = Backbone.View.extend({

    // define sane default values
    value  : '',
    title  : 'choose a value',
    radios : {},

    initialize: function(options) {

      // call out parent initialize method --> super.initialize(options)
      Backbone.View.prototype.initialize.call(this, options);

      // assign values from options
      this.value  = options.value   || this.value;
      this.radios = options.radios  || this.radios;
      this.title  = options.title   || this.title;

      // load and compile template
      options.template = options.template || $('#radioTemplate').html();
      this.tmpl = _.template(options.template);

      return this;
    },

    render: function() {
      // pick only the info we need to pass to the template
      var data = _.pick(this, 'title', 'value', 'radios');
      this.$el.html(this.tmpl(data));
      return this;
    }

  });

This is a pretty standard Backbone view. We define a RadioButtonView that inherits from Backbone.View using backbone’s extend method, which gives us something similar to the classical (in every sense of the word) inheritance paradigm. As you know, JavaScript has no notion of classes, and instead is based on prototypical inheritance, but we’ll get back to that latter.

On line 11 we just let our parent initialize all the view state -the scandalously verbose Backbone.View.prototype.initialize.call(this, options) just really means something like super.initialize(options)- and after that we perform our own initialization, letting the user override the View values using the options variable.

Notice that the template is just a string text waiting in the dom for us to read it with jQuery’s $ method, like this: $(‘#radioTemplate’).html(). We save it on a script tag to be sure that it won’t appear rendered on the page and we specify a type ‘text/template’ so that it won’t be accidentally executed by the browser.

For the render method we build a data object with just the info that the template needs (we don’t want the template to mess around with all the View’s info) using underscore’s pick function, and then update the dom using jQuery’s html method. Backbone automatically uses the el element we specify when instantiating the view to populate a jQuery element named this.$el.

After all that we just instantiate and render two groups of radio buttons.

// instantiate a radio button group with ages and render it
new RadioButtonView({
  el       : '#ageRadio',
  title    : 'enter your age',
  value    : '0-20',
  radios   : {
    '0-20'  : 'younger than 20',
    '20-50' : '20..50',
    '50-x'  : 'older than 50'
  }
}).render();

// instantiate a radio button group with genders and render it
new RadioButtonView({
  el       : '#genderRadio',
  title    : 'enter your gender',
  value    : 'female',
  radios   : {
    'male'   : 'male' ,
    'female' : 'female'
  }
}).render();

You can see all this code in action in this live jsFiddle: http://jsfiddle.net/opensas/ebjjj/

I know, everything seems to be going fine, but believe me, you have a time bomb ticking on your face just waiting for the right moment to explode…

tumblr_ll9shejNQH1qa7dx6

Scene two: the plot thickens

You are pretty proud of your reusable and generic radio button view, when another requirement drops in. Let’s say you have to dynamically add new options to the radio, perhaps from the user input or from some other component.

That’s a piece of cake, you say, and after a sudden inspiration you come out with this addRadio method:

addRadio: function(key, value) {
  value = value || key;
  this.radios[key] = value;
  return this.render();
}

Note: normally it would be considered a better practice to trigger some kind of model:changed event, and have the view listen on that event to call render. That way you would decouple the model from the view, and it would allow you to have more components listening on the radio items. But that subject deserves a whole article by itself.

Then we will add the gender and age radio items using our newly created method, like this:

  var ageRadioView = new RadioButtonView({
    el       : '#ageRadio',
    title    : 'enter your age'
  });

  // some user action or any other event
  // would trigger something like the following
  ageRadioView.addRadio('0-20', 'younger than 20');
  ageRadioView.addRadio('20-50', '20..50');
  ageRadioView.addRadio('50-x', 'older than 50');
  ageRadioView.value = '0-20';

  // same thing here
  var genderRadioView = new RadioButtonView({
    el       : '#genderRadio',
    title    : 'enter your gender',
    value    : 'female'
  });
  genderRadioView.addRadio('male', 'male');
  genderRadioView.addRadio('female', 'female');
  genderRadioView.value = 'female';

  ageRadioView.render();
  genderRadioView.render();

… and then…

duplicated input

BOOM!!! I told you this was going to happen…

watDuck
Here you can see the jsFiddle exploding right in your face: http://jsfiddle.net/opensas/zCyBz/

Note:

I’ve also made a complete example in which I set up a UI to let the user dynamically enter new radio items. There you can play with it and see JavaScript ‘magic’ in action. http://jsfiddle.net/opensas/YZGcA/

duplicated screen 2
This might be a good chance to see a slightly more elaborated Backbone sample. I created a FormView which displays an input for the key, another for the text of the new radio item to create, and a button to add the item. In that example you can also have a look at the way Backbone handles UI events from the view.

In this first article we’ve just prepared a pretty common JavaScript scenario, and talked a little bit about what’s coming next. I’m pretty sure many of you will already know by now what’s going on (I can’t be the only one who banged his head against this!).

In the next article we will have a look at an even simpler example and start playing around with the JavaScript console to find out what’s happening. To fully understand what’s going on, and find a suitable solution we’ll have to take a look at the way JavaScript passes around variables and it’s prototypical inheritance implementation.

About these ads
Tagged with: , , , ,
Posted in backbone, development, javascript

Leave a Reply

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

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: