Large-scale
Backbone apps
Bo Gotthardt
mail@gotthardt.bo
Backbone
Model
Collection
Events
Router
View
Not enough!
Model
var DocumentModel = Backbone.Model.extend({});
var document = new DocumentModel();
document.on("change:title", function (doc, newTitle) {
console.log("Title changed to", newTitle);
});
document.set("title", "Hello World");
Collection
var DocumentCollection = Backbone.Collection.extend({
model: DocumentModel,
url: "api/documents"
});
var documents = new DocumentCollection();
documents.on("add", function (doc) {
console.log("Got document from server", doc);
});
documents.fetch();
View
var DocumentView = Backbone.View.extend({
className: "document",
events: {
"click .save": "saveDocument"
},
render: function () {
// "The default implementation of render is a no-op."
},
saveDocument: function () {
// ...
}
});
var view = new DocumentView({
model: document
});
// Somehow render and attach to the right place in the DOM.
What's missing?
- Composable views
- App and view lifecycle
- Two-way binding
- Rich models
Can't do a modern large-scale app without those
How to get there?
Backbone plugin ecosystem
Assemble a set of plugins that does all of this
Marionette
Boilerplate-free ItemView
CollectionView
Pluggable views with Regions
Top-level Application
Views and regions
var DocumentView = Marionette.Layout.extend({
template: Handlebars.compile(template),
regions: {
imageBrowser: "#image-browser"
},
onRender: function () {
this.imageBrowser.show(new ImageBrowserView({}));
},
//...
});
region.show(new DocumentView({
model: document
}));
CollectionView
var TableView = Marionette.CollectionView.extend({
itemView: DocumentThumbnailView
});
var view = new TableView({
collection: documents
});
Stickit
Strightforward two-way binding
Binding setup in code enables clever tricks
Bindings setup
var DocumentView = Marionette.Layout.extend({
bindings: {
".title": "title",
".content": "content",
".alert.short-title": {
observe: "title",
visible: function (title) {
return title.length < 5;
}
}
},
// ...
});
And nothing binding-related in the HTML
Associations
Models with other models as properties
Parsing/serialization handled automatically
Relations
var DocumentModel = Associations.AssociatedModel.extend({
relations: [{
type: Associations.One,
key: "author",
relatedModel: AuthorModel
}, {
type: Associations.Many,
key: "comments",
collectionType: CommentCollection
}]
});
document.get("author").set("name", "John Smith");
document.set("author.name", "John Smith");
Other good ideas
- RequireJS for modularization
- RequireJS plugins for loading templates and CSS
- Would likely work well with TypeScript
- Organize classes by feature, not type!
Advantages
- More object-oriented
- Easier to get started with
- Easier to customize than monolithic frameworks
- Easier to debug than dirty-checking loops
Customization ideas
Region that slides in the new view on top of the old
Region shows a Promise for a view
Form validation visualized via bindings elements
Disadvantages
- Not an "out of the box" solution
- Not all plugins play well together
Questions?
Large-scale Backbone apps
By Bo Gotthardt
Large-scale Backbone apps
- 1,262