Thursday, 13 December 2012

Backbone.js for beginners

I really liked using Backbone.js, but I found the learning curve a little steep. I think this was because there was no middle ground tutorial between good (but rather stark) documentation and full blown solutions where no indication was given about the thinking behind how the application was developed.

I have devised this tutorial which, I hope, will help to bridge that gap and help you to understand why I think Backbone.js is excellent.

Backbone js - what and why?

Let's say you've been asked to make something that's going to use JavaScript. You're maybe a little nervous about the amount of time you have to do it in and you worry because you've seen work you did in the past turn into spaghetti when new requirements appear and when the look and feel of your project suddenly changes.

This is a common situation. Many of us start off with the best intentions when we start to write our code and become frustrated pretty quickly when we find the ideas we carefully laid out in the beginning don't scale well or just can't cope with the sheer variety of different requirements that appear in the lifetime of a project.

Enter Backbone. Backbone provides a framework onto which you can 'pin' your development work. It doesn't have a heavy footprint, weighing in at 3.9 kb and, if you follow its simple rules, you will find that your project gets larger and stays manageable.

Backbone uses MVC, which is a much lauded architectural pattern in software development. MVC stands for Model View Controller. This is not really the place to explain in depth how MVC works, but suffice it to say that MVC divides up what you are trying to do into Views (that which is exposed to the user), Models (managers of state) and Controllers (usually used to manage user interaction). More on MVC later when we actually start to make something.

Tutorial 

I think the easiest way to understand the thinking behind Backbone is to actually develop a small web application. I will try to communicate the way Backbone likes to do things and what is expected from you as a developer.

Ok, for our example, we're going to use JavaScript to allow the user to enter whatever they want into a form field and see the results printed out in grey on the same page. We're going to call our application Story Maker. I want to keep the example really simple so that we get the thinking right for when you get asked to do the hard stuff.


Our example does something very simple: when the fields are editing in the top box (which I call 'user details'), the results appear in grey in the bottom box (which I call the 'story')

The markup for the above is nothing special. We simply add two <div> tags to the page: one to contain the <input> boxes and another for the content to get injected into.









Here is the complete markup:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Backbone.js for beginners</title>
<style type="text/css">
body{
font-family:Verdana;
margin:30px;
}
label,input{
display:block;
}
label{
font-size:13px;
padding:10px 0 10px 0;
}
.variable_content{
color:#999;
}
#content, #user_details, h1{
border:1px solid #ddd;
margin:20px;
padding:20px;
width:400px;
}
</style>
</head>
<body>
<h1>Story Maker</h1>
    <div id="user_details">
            <label for="name">Please choose a name</label>
            <input type="text" id="name" name="name">
            <label for="name">Please choose an animal</label>
            <input type="text" id="animal" name="animal">
            <label for="name">Please choose an action</label>
            <input type="text" id="action" name="action">
    </div>
    <div id="content"></div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="https://raw.github.com/documentcloud/underscore/master/underscore.js"></script>
<script type="text/javascript" src="https://raw.github.com/documentcloud/backbone/master/backbone.js"></script>
<script type="text/javascript" src="https://raw.github.com/andyet/ICanHaz.js/master/ICanHaz.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
<script type="text/html" id="content_tmpl">
        <h2><span class="variable_content">{{ name }}</span>'s special day</h2>
        <p>One day, <i class="variable_content">{{ name }}</i> was walking down the road whistling a tune when he came upon a <i class="variable_content">{{ animal }}</i>.</p>
        <p>"Hello <i class="variable_content">{{ animal }}</i> !" he exclaimed and bent down to <i class="variable_content">{{ action }}</i> it.</p>
    </script>
</body>
</html>

The only thing you might notice is the strange script tag at the bottom of this markup. This is an 'icanhaz' template - a simple js templating solution. This contains the markup we want to inject into the 'content' div.

Find out more about Icanhaz here.

We are dealing with content (or data) here, so we want to be able to store it if we have to. In the MVC framework, the 'model' is responsible for handling data and informing views of changes in 'state' of that data. We want to be able to prepare for the possibility that what the user has entered may need to be stored somehow - be it in a database, some JS object or a cookie.

Remembering that Backbone expects us to define views and models in our project, we should think about how we are going to define our views. A view can be any interface that is available to the user - this means that a view could be some audio or visual indicator. In the case of this page, the view could be the whole page, or any small part of the page - you could make the view one input tag if you liked.

In our example, it's probably enough to define two Views: DetailsEntryView and StoryView. These are going to be the the two grey boxes you see above. Often in MVC, the controller is something that the user interacts with - be it a button, a slider or whatever, but in Backbone, this kind of Controller functionality is baked into the View.

 Let's start by writing our DetailsEntryView:


var DetailsEntryView = Backbone.View.extend({
    events: {
        'keyup input[type=text]':'setDataInModel'
    },
    initialize: function() {
        this.getDataFromModel();
    },
    getDataFromModel: function() {
         _.each($(this.el).find('input'),function(el){

            $(el).val(this.model.get($(el).attr('id')));
        },this);    
    },
    setDataInModel: function(e) {
        var inpt = e.currentTarget;
        this.model.set($(inpt).attr('id'),$(inpt).val());
    }
}),


First, we define our Class: DetailsEntryView which extends Backbone.View. Backbone provides this class with a method initialize but we can override it with our custom method if we want (and we do in this case).

When you make an instance of this class, you provide an id of the outermost container of your intended View.

This basically informs this Class that it's not going to be dealing with any elements outside of this area of the DOM.

The events object handles any user interaction with this View. It's very simple: rather than using jQuery to bind handlers to events, we use the built-in functionality that Backbone has to offer - you just provide the event, the element you want to target (this element MUST have the element you have specified as the container for this View as an ancestor) and the method you want to run.

The method you specify takes the event (e) as an argument as it should, and we use that to get the currentTarget.

You obviously can bind your own handlers if you want for more complex stuff (I'm thinking hover here), but for the simple handling we usually have to do it's fine.

We've made a method that gets called when the instance of DetailsEntryView is initialized. getDataFromModel basically populates the input boxes with default values on page load.

The setDataInModel method we've made is going to set the data in the Model. This is an example of how the Controller part of MVC is integrated into the View in Backbone because, in some implementations of MVC, the View communicated to the Controller and the Controller decides what should be updated in the Model. Backbone lets the View decide what it should send to the Model.

So, when you type a character into any of the input boxes, the setDataInModel method gets called and the contents of the input boxes get sent to the Model. Let's make our Model next.

We want a Model to hold our form details. Let's call it DetailsModel. Here's the code:

DetailsModel = Backbone.Model.extend({});

That really is all of it. We don't need any extra functionality here for our purposes. When we make an instance of DetailsModel, we pass in a data Object that will store our form content like this:

var mdl = new DetailsModel({name:"Harry",animal:"cat",action:"stroke"});

The name, animal and action properties get put into an attributes object inside our Model. This object can be inspected and modified using the get and set methods that are already built in to Backbone's Model functionality.

Knowing what our Model is, we can make an instance of our DetailsEntryView and pass in the instance of our Model like this:

new DetailsEntryView({id:'user_details',model:mdl});

This makes sense of the reference to: this.model in DetailsEntryView above. The Model we pass in is set as this.model internally by Backbone so we only have to write minimal code to set things up and Backbone takes care of the rest.

So that all takes care of the data transference and storage of our application. If you needed to, you could give the Model extra responsibility and allow it to store and load the data as you like. Backbone has methods to do that. I hope to make a new tutorial soon that shows all the possibilities that Backbone offers.

The only thing that's left is to output the data from the form back to the screen.

We've already decided that StoryView will handle this task. Here is the code:

StoryView = Backbone.View.extend({
    initialize: function() {
        this.model.bind("change", this.render, this);
        this.render();
    },
    render:function(){
        $('#content').empty().append(ich.content_tmpl(this.model.toJSON()));
    }
}),



No events Object because this is a dumb View in that it never communicates data. (That would be easy to add if, say, there was a requirement to have the text clickable in the output) We do have to add a handler that listens for change in our Model (yes - Views can share Models in MVC) and updates the DOM with our new data. render does that using the iCanHaz template described above. Notice how we are able to use the this.model.toJSON() method of the model to get all the content.

Here is the complete JS file:


var DetailsEntryView = Backbone.View.extend({
    events: {
        'keyup input[type=text]':'setDataInModel'
    },
    initialize: function() {
        this.getDataFromModel();
    },
    getDataFromModel: function() {
        _.each($(this.el).find('input'),function(el){
            $(el).val(this.model.get($(el).attr('id')));
        },this);    
    },
    setDataInModel: function(e) {
        var inpt = e.currentTarget;
        this.model.set($(inpt).attr('id'),$(inpt).val());
    }
}),
StoryView = Backbone.View.extend({
    initialize: function() {
        this.model.bind("change", this.render, this);
        this.render();
    },
    render:function(){
        $('#content').empty().append(ich.content_tmpl(this.model.toJSON()));
    }
}),
DetailsModel = Backbone.Model.extend({});

$(document).ready(function(){
    var mdl = new DetailsModel({name:"Harry",animal:"cat",action:"stroke"});
    new DetailsEntryView({el:$("#user_details"),model:mdl});
    new StoryView({el:$("#content"),model:mdl});
});


Wednesday, 12 December 2012

Sleuthing the IP address of your Raspberry Pi

I like to control my Pi from my Mac by ssh'ing in once I know the IP address.

In order to get a faster experience, I used a crossover cable to connect to my Mac but I never knew how to detect the IP address the Pi uses.

The answer is in a great article my friend sent me:

You just have to look in the contents of /private/var/db/dhcpd_leases by typing:

$ cat /private/var/db/dhcpd_leases

This will give you something like:
{
name=my-iPhone
ip_address=10.5.2.3
hw_address=1,54:1f:aa:72:f:d1
identifier=1,58:1f:aa:72:f:d1
lease=0x5558429e
}

...then you just scroll down the list until you see the name raspberrypi and take a note of the IP address.

Here's the article:
Raspberry Pi-ing, MacGyver Style
I'm looking forward to trying to get internet sharing working across the crossover connection too when I get the time. (it failed miserably last time I tried)

UPDATE: I tried using a normal network cable instead of the crossover as the article describes and it all works seamlessly - I was able to set up internet sharing as well.

Be aware that typing $ cat /private/var/db/dhcpd_leases may give you command not found if it can't find anything. Just reboot the Pi and it should return the details.

Perl Net::Bluetooth on Raspberry Pi

I wanted to use Perl to communicate via Bluetooth on my Raspberry Pi and a key module for that is Net::Bluetooth.

So I downloaded CPAN and attempted to install Net::Bluetooth from the prompt. It failed on the make part and suggested I download and install manually. This site is excellent for a walk through on how to install manually:

http://www.thegeekstuff.com/2008/09/how-to-install-perl-modules-manually-and-using-cpan-command/

Following these instructions also failed, with the install failing to find:

bluetooth/bluetooth.h

I tried everything to get this to work - even down to finding a 2011 version of Net::Bluetooth and trying that. In the end, it was an obscure post that suggested installing libc6-dev which you can do with apt-get install.  I don't know what this install does but it seems to deal with header files in some way.

Anyway, CPAN still would not install Net::Bluetooth, but when I tried manually installing again it worked. I wish I still had the URL of the post that helped me, but I couldn't find it again.

By the way, I suspect there may be something else up with my CPAN install on the Pi since it fails to install quite a lot of stuff so do try it first with CPAN because then you get all the dependencies as well whereas a manual install will mean that you have to also install the dependencies yourself.

Monkeys and Shakespeare

There's that quote which goes something like: If you put a monkey in front of a typewriter for long enough, it will eventually write some Shakespeare. Well, I'm like that too.

Whether I try to get Apache working, try to install a Perl module on my new Raspberry Pi (more on that here) or try and get a CMS on Rails to work, I come across problems. Sometimes they are difficulties that are easily searchable and a fix is immediate and other times it can just be a nightmare.

Often, it's just sheer bulldog like perseverance that carries me through and other times I come across a better way to solve it, but the reality is that computer code can be so complicated in ways that I won't ever understand and the only solution is to throw things at it and see what sticks.

So I thought I would start a technical blog and try and document the various solutions I came across for different problems that came up in the hope that I become one of those blogs that has exactly the answer you are looking for.

The posts are necessarily varied since my interests and work requirements change constantly but hopefully someone will get something out of one small part.