I'm also learning how to use CoffeeScript, which is close enough to python/ruby for me to understand.
First thing that I noticed is that most of the examples for Backbone out there are in pure JavaScript, so I thought I'd do my bit by providing something in CoffeeScript.
To that end, here is a very simple app which displays a number. You can increase or decrease the count by clicking buttons.
The app.coffee code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.app = {} | |
app.controllers = {} | |
app.models = {} | |
app.views = {} | |
class window.MainController extends Backbone.Controller | |
routes : | |
"": "home" | |
"home": "home" | |
home: -> | |
app.views.counter.render() | |
class window.Counter extends Backbone.Model | |
defaults: | |
count: 0 | |
class window.CounterView extends Backbone.View | |
initialize: -> | |
@counter = new Counter() | |
@render() | |
el: $('#counter') | |
events: | |
'click button#inc-count' : 'inc' | |
'click button#dec-count' : 'dec' | |
render: -> | |
$(@el).find("#count").html "The count is " \ | |
+ @counter.get("count") | |
@ | |
inc: -> | |
ct = @counter.get("count") | |
@counter.set(count: ct+1) | |
@render() | |
dec: -> | |
ct = @counter.get("count") | |
@counter.set(count: ct-1) | |
@render() | |
head.ready -> | |
app.controllers.main = new MainController() | |
app.views.counter = new CounterView() | |
app.models.counter = new Counter() | |
Backbone.history.start() | |
and the html to go with that:
In detail
At the top, we set up global hashes to store our objects. In a bigger app this would make referencing bits and pieces much easier, although we don't really need it in this example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.app = {} | |
app.controllers = {} | |
app.models = {} | |
app.views = {} |
Next the controller. This one is almost empty except it has two routes both taking you to the home control which is also part of the controller. The route with no reference (the empty string) and the one for #home tagged on the end of your URL (by way of an example) both call the home function in this case.
The home control just tells the view to render itself.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class window.MainController extends Backbone.Controller | |
routes : | |
"": "home" | |
"home": "home" | |
home: -> | |
app.views.counter.render() |
Next the Counter model which has one attribute called count which defaults to zero. In reality I think you would want to synchronize your models with a database, but we'll do that in another post soon.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class window.Counter extends Backbone.Model | |
defaults: | |
count: 0 |
And now for the View. The View is obviously what you are seeing in the browser. In our trivial example we only have one view, but a real app would probably have several. A view lumps together a unit of the app, sometimes nowadays we call these widgets, or blocks or display regions or whatever. You get the idea.
In the initialize function, we just connect the view to the model that backs it. The events connect the button to the functions that they call. The render function draws the result into the #count div; the @ symbol at the end is shorthand for this. In CoffeeScript (like Ruby) the last line of a function gets returned even if you don't specifically say "return". So in other words it means "return this". This is handy since it lets us chain together functions.
The inc and dec functions increase and decrease the count in the model and then update the display. Please see the update here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class window.CounterView extends Backbone.View | |
initialize: -> | |
@counter = new Counter() | |
el: $('#counter') | |
events: | |
'click button#inc-count' : 'inc' | |
'click button#dec-count' : 'dec' | |
render: -> | |
$(@el).find("#count").html "The count is " \ | |
+ @counter.get("count") | |
@ | |
inc: -> | |
ct = @counter.get("count") | |
@counter.set(count: ct+1) | |
@render() | |
dec: -> | |
ct = @counter.get("count") | |
@counter.set(count: ct-1) | |
@render() |
Finally the equivalent of the main() function which instaniates the bits and bobs and then starts the history. I've no idea why they called it history, but basically it starts up all the listeners.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
head.ready -> | |
app.controllers.main = new MainController() | |
app.views.counter = new CounterView() | |
app.models.counter = new Counter() | |
Backbone.history.start() |
That's all for now. Next time I'll show you how to connect all this to your database using python and Flask.
If you see anything wrong with what I've written here or if you spot spelling or other mistakes then please let me know.
Very interesting.
ReplyDeleteIn new versions of backbone 'Backbone.Controller' has become 'Backbone.Router'.
Thanks for the tutorial.
ReplyDeleteIs the following line near the bottom redundant? The line above creates a Counter object when the CounterView gets initialized, so is this Counter object needed?
app.models.counter = new Counter()
It's still pre-coffee here, but no I don't think it is. Well spotted.
ReplyDeleteLike the blog btw.
Cool, I just started my CoffeeScript journey not more than a week ago, and I'm already using it in conjunction with Backbone.js as well. Happy to see I'm not alone :)
ReplyDeleteI see you use the app namespace as best practises preach. Have you seen this namespace helper by elegant code: http://elegantcode.com/2011/01/26/basic-javascript-part-8-namespaces/
Oh, and by the way: I wrote up a short case description on a Backbone.js project I worked on not too long ago, where I used Backbone.js not with JSON data, but content that was already rendered server-side. My method was to render a bunch of HTML5 data attributes that I read in JavaScript and create my models around allowing me to render sub-views etc. You can find it here if you're interested: http://ahrengot.com/work/skive-festival-website-2012/#/all/backbone
Where's the html code? It seems you forgot to add the link...
ReplyDeleteGreat & Useful Articles
ReplyDeleteBackbone.js Course | Backbone.js Training | Backbone.JS Online Course | Backbone.JS Training in Chennai