- A library designed to be minimalist and useful in a wide variety of situations (non-opinionated)
- Based in events communication/syncronization
- Based in MVC (Model-View-Controller) structure
Models are the heart of any application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control.
Backbone.Model provides a basic set of functionality for managing changes.
// Namespace definition
var SL = SL || {};
SL.Models = SL.Models || {};
SL.Views = SL.Views || {};
SL.Collections = SL.Collections || {};
SL.Router = SL.Router || {};
// Model definition
(function () {
'use strict';
SL.Models.Product = Backbone.Model.extend({
urlRoot: function() {
// In this case, POST to '/donuts' and PUT/GET to '/donuts/:id'
return this.id ? '/products/' + this.id : '/products';
},
defaults: {
title: '',
quantity: 0,
available: false
},
initialize: function(options) {
// Do some initialization stuff...
options = _.merge(defaults, options);
// Register events...
this.on('change:title', function(model){
alert(
capitalize(model.get('title'))
);
});
},
validate: function(attrs) {
if(attrs.title.length < 0){
return 'Name can\'t be blank';
}
}
});
var product = new SL.Models.Product({ id: 1 });
product.fetch({
success: function(prod) {
prod.title = 'BluRay'
prod.save();
// PUTs the product beacause of the existent id
// { id: 1, title: 'BluRay', ... }
}
});
var newProduct = new SL.Models.Product({ title: 'Super Awesome DVD' });
newProduct.save();
// POST new product
// { id: 2, title: 'DVD Bacana', quantity: 0, available: false }
})();
Is a structure of set of models with some functions.
// Collection definition
(function () {
'use strict';
SL.Collections.ProductsCollection = Backbone.Collection.extend({
// Use its model to deserialize and add methods configured on the model
model: SL.Models.Product,
url: '/products',
initialize: function(options) {
// Do some initialization stuff...
},
available: function () {
return this.select(function(product) {
return product.get('available') == true;
});
},
unavailable: function () {
return this.select(function(product) {
return product.get('available') == false;
});
}
});
var products = new SL.Collections.ProductsCollection();
products.available();
products.unavailable();
})();
Is the Controller of MVC design pattern. It's called VIEW because it handles the rendering.
Provides a template library.
// View definition
(function () {
'use strict';
SL.Views.ProductView = Backbone.View.extend({
el: '.product',
collection: SL.Collections.ProductsCollection,
render: function() {
// Do a lot of manipulations and insert on the dom
}
});
})();
Is a component to map a url to a function.
// Routing definition
(function () {
'use strict';
SL.Router = new Backbone.Router({
routes: {
'products': function() {
// do stuff
}
}
});
})();
When a Backbone application grows, maintaining it requires adding structure, adding boiderplate code, either through a custom set of conventions and components, or based on somebody elses framework.
- Is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications using: modular, event driven, messaging bus architecture
- Is a Collection of common design and implementated patterns
-
Standardize the rendering process: Without any additional configuration, it will take a template that you specify with a View's template property, compile it with Underscore's templating function and pass it a model or collection.
-
Consistent View lifecycle: Views are initialized, rendered, shown, refreshed and destroyed.
-
Ability to define ad manage complex layouts: Marionette provides regions objects that define portions of the DOM that can display and swap out Views.
-
Helper to help DRY out the code: Marionette provides hooks to allow you to abstract details of the DOM.
-
Central Application initialization: Marionette provides the hability to set initializers that will run before the application start.
-
Memory management: Marionette resolves some memory leaks cause by Backbone.js.
this.WL = (function(Backbone, Marionette){
var App = Marionette.Application.extend({
container: 'body',
// The hability of define regions that can be sub-modules
regions: {
headerRegion: '[data-attribute=header-region]',
sideBarRegion: '[data-attribute=sidebar-region]',
mainRegion: '[data-attribute=main-region]'
},
initialize: function(options) {
// Do some initialization stuff...
},
onStart: function() {
this.module('HeaderApp').start();
this.module('SideBarApp').start();
this.module('MainApp').start();
}
});
return new App();
})(Backbone, Marionette);
// App Start
$(document).ready(function() {
WL.start();
});
this.WL.module('HeaderApp', function (HeaderApp, App, Backbone, Marionette, $, _) {
this.startWithParent = false;
var API;
API = {
show: function() {
HeaderApp.Show.Controller.showHeader();
}
};
// Message Bus Pattern
HeaderApp.on('start', function(){
API.show();
});
return HeaderApp;
});
this.WL.module('HeaderApp.Show', function(Show, App, Backbone, Marionette, $, _) {
Show.Controller = {
showHeader: function() {
var headerView = this.getHeaderView();
App.headerRegion.show(headerView);
},
getHeaderView: function() {
return new Show.Header();
}
};
return Show.Controller;
});
this.WL.module('HeaderApp.Show', function(Show, App, Backbone, Marionette, $, _) {
Show.Header = Marionette.ItemView.extend({
template: _.template('<div>Welcome aboard {{ name }}! <a class="login">login</a></div>'),
defaults: {
name: 'Visitor'
},
ui: {
loginButton: 'a.login'
},
events: {
'click @ui.headerButton' : 'login'
}
initialize: function(options) {
this.mergeOptions(options, this.defaults);
},
onRender: function() {
// Is executed when the render method has completed
this.$el.addClass(this.id);
}
login: function() {
// Do login stuff...
}
});
return Show.Header;
});
this.WL.module('HeaderApp.List', function(List, App, Backbone, Marionette, $, _) {
List.LinkView = Marionette.ItemView.extend({
template: _.template('<a class="super-link" href="{{ link_url }}">{{ link_name }}</a>'),
// If you want to override the default serialization
serializeData: function() {
return {
link_name: this.model.get('name'),
link_url: this.model.get('url')
};
}
});
List.LinkCollectionView = Marionette.CollectionView.extend({
template: 'path/to/template.jst',
childView: List.LinkView
});
return List;
});
Provides a cache for retrieving templates from script blocks in HTML. This will improve the speed of subsequent calls to get a template.
(function () {
var template = Marionette.TemplateCache.get('.super-link', options);
template({
link_name: 'My Lists',
link_url: 'http://example.com/my-lists'
});
})();
- Event-Oriented Architecture
- Active Development
- Large core team
- Large community
- Many companies use it
- Dev Tools extension: Marionette Inspector for Chrome
- Avoid boilerplate involved in writing Backbone apps
- Reusable chuncks of UI logic
- Focus only large scale applications