Is your web app drowning in a sea of JavaScript? Has your client-side codebase grown from "a snippet here and there" to "more JavaScript than HTML"? Do you find yourself writing one-off snippets instead of generalized components? You're not the only one. Learn about a handful of strategies you can use to keep your JavaScript codebase lean, modular, and flexible. We'll cover all the major pain points — MVC, templates, persisting state, namespacing, graceful error handling, client/server communication, and separation of concerns. And we'll cover how to do all this incrementally so that you don't have to redo everything from scratch.
17. WISH:
Code that accomplishes a single task
should all live together in one place.
THEREFORE:
Divide your codebase into components,
placing each in its own file.
19. WISH:
We should be able to rewrite a component
without breaking things elsewhere.
THEREFORE:
A component should be whatever size is
necessary to isolate its details from other code.
20. A “component” is
something you could
rewrite from scratch
without affecting other stuff.
29. WISH:
We should be able to rewrite a component
without breaking things elsewhere.
THEREFORE:
We should standardize the way
components talk to one another.
48. The auto-completer knows
about the menu…
var menu = new S2.UI.Menu();
menu.addChoice("Foo");
menu.addChoice("Bar");
someElement.insert(menu);
menu.open();
49. …but the menu doesn’t know
about the auto-completer
menu.observe('ui:menu:selected', function(event) {
console.log('user clicked on:', event.memo.element);
});
66. Models
define a model class window.Todo = Backbone.Model.extend({
EMPTY: "new todo...",
property access wrapped in set/get methods initialize: function() {
if (!this.get('content'))
this.set({ 'content': this.EMPTY });
},
toggle: function() {
this.set({ done: !this.get('done') });
},
triggered when the object is saved validate: function(attributes) {
if (!attributes.content.test(/S/))
return "content can't be empty";
},
// ...
});
67. Views
define a view class window.Todo.View = Backbone.View.extend({
tagName: 'li',
bind events to pieces of the view events: {
'dblclick div.todo-content' : 'edit',
'keypress .todo-input' : 'updateOnEnter'
},
initialize: function() {
map to a model object; re-render when it changes this.model.bind('change', this.render);
},
set the view’s contents render: function() {
// ...
},
// ...
});
68. Synchronization
Backbone.sync = function(method, model, yes, no) {
determine the HTTP verb to use for this action var type = methodMap[method];
serialize the object to JSON var json = JSON.stringify(model.toJSON());
send the data to the server $.ajax({
url: getUrl(model),
type: type,
data: json,
processData: false,
contentType: 'application/json',
dataType: 'json',
success: yes,
error: no
});
};
69. Other options:
SproutCore
(http://sproutcore.com/)
Cappuccino
(http://cappuccino.org/)
JavaScriptMVC
(http://javascriptmvc.com/)