Ampersand.js
If there was a backbone 2.0, this would be it
Originally given as a
Lightning Talk
by Mike Macaulay
Agenda
What is it?
My Experiences
How you can start using it today
Backbone is great!
it's simple
un-opinionated
Couple of pain points
Attempted to be solved by:
Marionette.js
Backbone Relational
ModelBinder
Sticket
on and on...
What makes it different?
Node Inspired
Separate out Models, Views, Router
CommonJS format
NPM / Browserfy
ES5 Features
Lot's of nice features
Enough Already
Show me some code!
Backbone Model
/** Person
* firstname : string
* lastname : string
**/
var Person = Backbone.Model.extend({
getFullName : function(){
return this.get('firstname') + ' ' + this.get('lastname');
}
});
Introducing Ampersand State
var Person = AmpersandState.extend({
props: {
firstName: 'string',
lastName: 'string'
},
session: {
signedIn: ['boolean', true, false],
},
derived: {
fullName: {
deps: ['firstName', 'lastName'],
fn: function () {
return this.firstName + ' ' + this.lastName;
}
}
}
});
PropertieS
var Person = AmpersandState.extend({
props: {
firstName: ['string', true, 'Billy']
lastName: {type:'string',
required:false,
default:'mac'}
}
});
var person = new Person({firstName : 'Mike'});
person.firstName = 'Mikey'; // or person.set('firstName','Mikey');
person.firstName = new Date() // throws error!
Session Properties
var Person = AmpersandState.extend({
props: { // first and last name },
session : {
signedIn : 'boolean'
}
});
var person = new Person({});
person.signedIn = true;
person.toggle('signedIn'); // toggle!
person.toJSON() // => // won't include signedIn
Derived Properties
var Person = AmpersandState.extend({
// first and last name
derived: {
fullName: {
deps: ['firstName', 'lastName'],
fn: function () {
return this.firstName + ' ' + this.lastName;
}
}
}
});
var person = new Person();
person.on('change:fullName', callback);
Plus much more
- Child Models
- Child Collections
- Event Bubbling from children
Ampersand Views
Kind of like Backbone Super views...
Views
- Automatic Model Binding
- Always expects a template
- Extends from Ampersand State
- Can handle child views
Model Binding
var PersonView = AmpersandView.extend({
templates: templates.person,
bindings: {
'model.name': {
type: 'text',
hook: 'name'
},
'model.age': '[hook=age]', //shorthand of the above
}
});
A common Pattern
Template:
...
<button class="save-button">Save</button>
...
View Code:
var View = Backbone.View.extend({
events : {
'click .save-button' : 'onSave'
}
});
Problem is...
I've now mixed up my css and javascript together.
No one knows what can be changed
Using the Data-Hook Attribute
Template:
<button data-hook="save" class="whatever-i-dont-care">Save</button>
Ampersand View:
var View = AmpersandView.extend({
events : {
'click [data-hook="save"]' : 'onSave'
}
});
Plus Much More
- Cached Elements
- SubView management
- Form management
- View Switcher (a la marionette regions)
Still interested?
Much more than just Models and Views
Why I'm excited about it
Upgrade Path from Backbone
Solves many major pain points
Still Flexible
We're using it today!
From ampersand.js home page
Experience
Ampersand and Backbone live perfectly side by side
var MyAmpersandView = require('path-to-ampersand-veiw');
Marionette.Layout.extend({
regions : {
foo : "[data-region=foo]"
},
onRender : function(){
this.foo.show(new MyAmpersandView());
// just works!
}
Experience
So we took the plunge..
Replaced all our models with Ampersand Models
All new views are Ampersand views.
We still like Marionette Layouts though...
so we keep using those.
No problem either way.
Ok, so how do i Use it?
You may have noticed...
npm / browserify
I use require.js. Am I screwed?
No, just kidding
It's relatively easy to bring ampersand into your require.js project.
Fully running example contributed by yours truly:
https://github.com/AmpersandJS/examples
Final thoughts
Advantages of a loosely coupled architecture.
Using the best tool for the job.
Virtual Dom as an example.