Two headaches explained when you’re getting started with backbone.js

by Cedric Dugas on August 22, 2011

Recently I decided to dive into backbone.js. I tried to write a small project with it but I found it was hard to get into and abandoned. After seeing a presentation of it at JS-Montreal, I finally decided to give it another try and started porting a project I was working on to it.

Personally I find that backbone.js is a weird beast. It’s called an MVC framework, but there is no controller, the events system is completely different from your default PHP/Ruby MVC style and there is a notion of collections. Basically Backbone is a MRVT(Model Route Views Template), scratch that, it’s in fact a MCRVT(Model Collection Route View Template)

So if you are a front-end developer with some MVC knowledge because you are sometimes dealing with a back-end framework you will probably be completely lost. Then you start reading the doc, it seems good and gets you 80% there, but trying to start only with the doc will probably end in pain. Then you go to the todo app example, you understand a little bit more the concepts but there is still lot of WTF.

Then, you search for tutorials, the nettuts tutorial is particularly good. But personally I had problems with what is not really explained in those tutorials, I guess you could call that “edges cases”. Only the videos at peepscode (Did not want to do promotion, but credits where it is due) where successful at really showing me all the power of backbone and really helped me understand all the underlying concepts that come with that.

So anyway, what was the 2 problems I have been struggling with? Well for one when I was binding a collection to a method within my view, I would lose the this reference to my view in that method, and also, my events would not bind to my views and would just never fire.

Events Binding In The Views

In backbone, the views control all the events that are happening “in this part of html code” (in other words, your associated template). Which is really good for decoupling your code, and makes for a very good code structure. Events are handled automatically with jQuery delegates, thing is, the dom element that delegates all the events need to be outside the view, something I did not understand at first. It makes also no sense to me that I can’t delegate my events from within my view, what happen if the view is a popup? I don’t want to delegate to the document.

Fortunately something you can do after your view content is rendered is changing the this.el element to the view container and call this.delegateEvents(this.events) . That took care of the event binding problem.

Update from Josh comment:
If you assign ‘el’ directly to the view and remove it from render, the dom element that delegates all the events will be part of your view. Based on your example, do:

wedapp.view.TasksForm = Backbone.View.extend({
el: $(“.dialogForm”),
…You can then remove this.delegateEvents from render as well.

Example:

wedapp.view.TasksForm = Backbone.View.extend({
	events: {
		"click #completedbtn" : 	"complete",
		"click #updatebtn" : 		"update",
		"click #savebtn" : 			"save",
		"click #closebtn" : 		"close",
	},
	render: function() {
		var data = (this.model.has("name") ) ? this.model.toJSON() : this.model.default;
		var formString = this.template(data);
		$(formString).dialog({
			autoOpen: true,
			height: 460,
			width: 350,
			title:"Tasks",
			modal: true
		})
		this.el = $(".dialogForm");
		this.delegateEvents(this.events)
		return this;
	},
	initialize : function(){
		_.bindAll(this,"render")
		this.template = _.template($("#task_form_tpl").html());
		this.render().el;
	},
	complete: function(){
		console.log("crap")
	},
	update: function(){
	},
	save: function(){
	},
	close: function(){
	},
});

Weird Custom Events Behaviors

Backbone has a custom events system baked-in which makes it really simple to handle model states. This is really powerful since when you update a row in your database, for example, the html for that row would be automatically rendered back when you change the data. No DOM data tags non-sense.

Problems is, doing this.collection(‘reset’, handleCollection) changes the this handle to the collection! I was wondering why in handleCollection() I could not call any other method from my current view. Of course I logged this to see what was happening, but since backbone is very particular of what it returns I did not see that handleCollection was returning the collection instead of the view object.

What you need to do for retaking control of this, is to bind it to the view in the initialize method like this: _.bindAll(this,”handleCollection”) . Personally I don’t think it makes sense to handle it that way and it pains me to add this code, but here is no other way that I know of.

Update from Josh comment:
If you want to bind your collection to a callback event, do: this.collection.bind(‘reset’, this.handleCollection, this)

If you pass “this” as the third parameter, you won’t need to do your _.bindAll() in initialize for that method. I’m assuming here that handleCollection is a method in the view.

Hope it helps!

I am a bit disappointed that backbone.js is so hard to get started with. It introduces a lot of concept to front-end developers and do not have enough tools to guide you around.

I think tutorial videos through each sections would really help a lot the beginners understanding all the underlying concepts of backbone, I even thought about doing some myself but I’m too much inexperience with it to do that. In fact I think that a getting started guide like rails for zombies would be perfect, but hey, I know it is a lot of work :P



4 comments

I think you were right in all of your assumptions, just didn’t have everything in the right spot.
If you assign ‘el’ directly to the view and remove it from render, the dom element that delegates all the events will be part of your view. Based on your example, do:

wedapp.view.TasksForm = Backbone.View.extend({
el: $(“.dialogForm”),

You can then remove this.delegateEvents from render as well.

If you want to bind your collection to a callback event, do:

this.collection.bind(‘reset’, this.handleCollection, this)

If you pass “this” as the third parameter, you won’t need to do your _.bindAll() in initialize for that method. I’m assuming here that handleCollection is a method in the view.

by Josh Vermaire on August 23, 2011 at 9:10 am. Reply #

Ahhhhh, well that clear lots of confusions :P , will update the post later

by admin on August 23, 2011 at 9:25 am. Reply #

I want to working working with backbone.js & PHP. But i can’t able to find single example for it. So please provide the example with source code(backbone+PHP).

by Senthil Pandian on October 17, 2011 at 6:20 am. Reply #

Great article. I had a similar experience to you. Events were quietly being ignored. I’d been caught out by the fact that unless you specify a view’s element and the element exists, backbone creates a view’s element for you, but doesn’t attach it to the DOM (for performance reasons, apparently).

“this.el is created from the view’s tagName, className, and id properties, if specified. If not, el is an empty div.”
http://documentcloud.github.com/backbone/#View-el

by Mark on October 25, 2011 at 1:21 am. Reply #

Leave your comment

Required.

Required. Not published.

If you have one.