Backbone + Handlebars component system.
-
To install with
npm
, add to project's package.json"dependencies": { "backbone-component": "git+https://github.com/CSNW/backbone-component.git#v0.3.5" }
-
Require or import backbone-component
var BackboneComponent = require('backbone-component'); // BackboneComponent.Component, .View, .Computed, ... import {Component, View, Computed, ...} from 'backbone-component';
import { Component } from 'backbone-component';
const template = Handlebars.compile(`Hello {{get props "name"}}`);
// ^ get helpers is used to get value from model
const SayHiComponent = Component.extend({
template,
// Component receives props from parent view
// (defaultProps will be merged into these props)
defaultProps: {
name: 'World'
}
});
// Register component as helper for usage from Handlebars
SayHiComponent.registerAs('say-hi');
import { View } from 'backbone-component';
const template = Handlebars.compile(`Message: {{say-hi name="Universe"}}`);
export default View.extend({
template
});
import { Component } from 'backbone-component';
const InputComponent = Component.extend({
tagName: 'input',
defaultProps: {
value: null
},
events: {
change: 'handleChange'
},
initialize() {
// Binding is stored internally in props model,
// so component treats this.props like standard Backbone Model
this.listenTo(this.props, 'change:value', this.render);
},
render() {
this.el.value = this.props.get('value');
},
handleChange(e) {
this.props.set({ value: e.target.value });
}
});
InputComponent.registerAs('input');
import { View } from 'backbone-component';
const template = Handlebars.compile(
`Name: {{input value=(bound model "name")}}`
);
export default View.extend({
template,
initialize() {
this.model.set({ name: 'Tim' });
}
});
import { Component } from 'backbone-component';
const template = Handlebars.compile(`{{get props "message"}}`);
const DisplayMessage = Component.extend({
template,
initialize() {
// computed is binding + fn, so use binding approach
this.listenTo(this.props, 'change:message', this.render);
}
});
DisplayMessage.registerAs('display-message');
import { View, computed } from 'backbone-component';
const template = Handlebars.compile(`
Quiet: {{display-message message=quiet}}
Yelling: {{display-message message=(computed (bound model "message") toUpperCase)}}
{{! ^ computed can be used inline in combination with bound}}
`);
export default View.extend({
template,
initialize() {
this.model.set({ message: 'Hello World' });
// Create computed value
this.quiet = computed(this.model, 'message', this.toLowerCase);
},
toLowerCase: message => message.toLowerCase(),
toUpperCase: message => message.toUpperCase()
});
import { Component } from 'backbone-component';
const template = Handlebars.compile(`
<dt>{{get props "title"}}</dt>
<dd>{{outlet}}</dd>
`);
const DetailsComponent = Component.extend({
template
});
DetailsComponent.registerAs('details');
import { View } from 'backbone-component';
const template = Handlebars.compile(`
{{#details title="Information"}}
<p>In outlet...</p>
{{/details}}
`);
export default View.extend({
template
});
Models, Bindings, and Computed:
{{get model "key"}}
or{{get binding}}
- Get underlying value for Backbone Model, Binding, or Computed(bound model "key")
- Create a two-way binding to the given model and key(oneway model "key")
- Create a one-way (get only) binding to the given model and key(computed binding fn)
or(computed value fn)
- Map the given binding/value through the given function
Components and Views:
{{outlet}}
- Outlet for block components{{render view}}
- Render given view in template{{placeholder "id"}}
- (internal) Insert placeholder to be replaced in render
Utilities:
(eq a b)
- Check if two values are equal (using==
) (e.g.{{#if (eq a b)}}...{{/if}}
(not c)
- Get inverse of value (using!
)(array 1 2 3)
- Create array from values(object a=1 b=2)
- Create array from key-values