Javascript is increasingly a larger and larger piece of logic and application building on both front-end and back-end technologies. To help maintain and iterate pre logic and modularity, some MVC patterns have crept into popularity over the past few years. One such popular MVC framework is Backbone.js.
Models, Views, and Controllers under Backbone
Backbone.js has these main functions:
- Create models (and collections of models)
- Create views
- Manage bindings and events that allow modular use of different models or views with other pieces of the framework.
- Make use of the observer pattern on the models, so views can directly listen to any changes that happen to a model and automatically update that view to reflect the changes
- Built in support for jQuery or Zepto for DOM manipulation
Part 1: Models
Let's create a model to hold data about a person.
Person = Backbone.Model.extend({
// your constructor for the Person instance
initialize: function() {
console.log('hello world');
}
});
var p = new Person();
Easy right? Now... let's add in some parameters to provide more data for our Person.
var p = new Person({name: "Matt", height:'6\'2"'});
console.log(p.get('name'));
But our model isn't setup to have default attributes when we don't have inputs describing the name and height. Let's add that now.
Person = Backbone.Model.extend({
initialize: function() {
console.log('hello world');
},
defaults: {
name: "Mark",
height: "3\""
}
});
var p = new Person();
p.set({name: "Matt", height: "6'2\""});
console.log(p.get("name"));
One of the best features of Backbone lies in the ability to trigger updates in the views automatically when the model's data has changed. Binding is powerful.
Person = Backbone.Model.extend({
initialize: function() {
console.log('hello world');
// add a binding to the change of the name property
this.bind("change:name", function() {
console.log(this.get('name') + " is now the value for name");
});
},
defaults: {
name: "Bob Hope",
height: "unknown"
}
});
We also might like to make sure that data included with a Backbone model is valid before we allow its creation.
Person = Backbone.Model.extend({
initialize: function() {
console.log('hello world');
this.bind("change:name", function() {
console.log(this.get('name') + " is now the value for name");
});
// add a binding to the error, too
this.bind('error', function( model, error ) {
console.error(error);
});
},
defaults: {
name: "Bob Hope",
height: "unknown"
},
validate: function ( attributes ) {
if( attributes.name == 'Joe' ) {
// an error message
return "Uh oh, you're name is Joe!";
}
}
});
var person = new Person();
person.set({name: "Joe", height:"6 feet"});
console.log(person.toJSON());
Part II: Views
The HTML (in Jade template)
#container
button Load
ul#list
#list-template
li
a(href="")
The Backbone
// a simple model
var Links = Backbone.Model.extend({
data:[
{ text: "Google", href: "http://google.com" },
{ text: "Facebook", href: "http://facebook.com" },
{ text: "Youtube", href: "http://youtube.com" }
]
});
var View = Backbone.View.extend({
// create our constructor
initialize: function () {
console.log('init');
}
});
var view = new View();
So let's star with options for the View.
var View = Backbone.View.extend({
// options --> object supplied to the constructor
initialize: function () {
console.log(this.options.blankOption);
}
});
var view = new View({ blankOption: "empty string" });
view.blankOption /// empty string
There are also special pre-built options. The el parameter will allow you to attach this view to an element already on the page.
var View = Backbone.View.extend({
initialize: function () {
console.log(this.options.blankOption);
// this.el -> #list in the DOM
}
});
var view = new View({ el: $("#list") });
You can also create a new element with:
var View = Backbone.View.extend({
initialize: function () {
console.log(this.options.blankOption);
// this.tagName --> create a "tagName" item in the DOM
$('body').append(this.el)
}
});
var view = new View({ tagName: 'div', className: 'class', id: '', attributes: '' }); // --> creates a div tag with class "class"
For now, we will use a static, nonchanging target.
var View = Backbone.View.extend({
initialize: function () {
console.log(this.el);
},
el: '#container'
});
var view = new View({ model: new Links() }); //from first snippet
Now let's add some events.
var View = Backbone.View.extend({
initialize: function () {
// do nothing
// render() would just be calling render twice
},
el: '#container',
events: {
"click button": "render"
},
render: function() { // function commonly called by Backbone
var data = this.model.get('data');
for (var i=0, l=data.length; i<l; i++){
var li = this.template
.clone()
.find('a')
.attr('href', data[i].href)
.text(data[i].text)
.end();
this.$el // <-- this.$el is the jQuery object for View's element, this.el is the DOM object
.find('ul#list').append(li);
}
}
});
//from first snippet
var view = new View({ model: new Links() });
Part III: Routers
Routers will help us provide navigation and control to give instructions to your web app. Adding sub-URLs or hashtags can help navigate your app, and provide quick inward looking URLs that pen up certain features of your app.
var Router = Backbone.Router.extend({
routes: {
// this will match any url with foo/<param> and provide :bar: as the parameter to the function paramtest
// : will match only the next URI segment
// so browsing to #foo/1 will call paramtest(1)
"foo/:bar" : "paramtest",
/ * will match the entire URI segments left, so #a/b/c will call func("a/b/c")
"*action" : "func"
},
func: function (action) {
console.log(action);
},
paramtest:function (p) {
console.log(p);
}
});
new Router();
// required in order to parse the hashtags
Backbone.history.start();
Pretty simple!
Part IV: Collections
Collections provide mechanisms for groupping mutliple instances of Models, providing powerful features to maintain and collect data into lists.
// our basic Person Model
var Person = Backbone.Model.extend({
// run when we create a Person
initialize: function() {
console.log('Person is initialized.');
},
// default attributes
defaults: {
name: 'undefined',
age: 'undefined'
}
});
// create our Collection!
var People = Backbone.Collection.extend({
// run when our collection is created
initialize: function() {
console.log("People Collection is initialized");
},
// define what model will make up our collection
model: Person
});
// create a new Person
var person = new Person({name:"Joe"});
// establish a collection and add our Person to our collection
var people = new People(person);
people.add([{name:"Bob"}, {name:"Jim"}]);
// print out our list of models
console.log(people.toJSON());
And there we are, a usable Collection that maintains Models and their Views. Please let me know in the comments of anything I missed or should add!
Post a Comment
Comments ()