riblet
v0.0.9
Published
A lightweight Backbone framework
Downloads
4
Readme
What
Riblet.js is a lightweight Backbone framework. It is not meant to be a competitor with something like Marionette. It's use case is to round out some of the sharper edges of Backbone such as it's lack of subviews, associations, and a true view lifecycle.
NOTE: This is a developer preview. Not all features in the docs are complete or implemented yet.
API
Riblet.Model
Getters
The Riblet.Model provides a getters
. This allows for more advanced get
s for certain properties. Getters are especially useful for doing simple associations.
Getters and templating
Getters also work as expected with templates. If you add a fullName
getter to the getters
hash for example, you could then do {{fullName}}
in your template and it'll use the getter lookup to figure it out.
Note, however, that getters can be overridden by templateHelpers
which are part of Riblet.View. So, if you had a fullName
getter that returned firstName + lastName
and then a templateHelper that returned lastName + ', ' + firstName
and you had a {{fullName}}
tag it'd return Godson, Oscar
(templateHelper
) instead of Oscar Godson
(getter)
Simple Example:
var myModel = Riblet.Model.extend({
getters: {
fullName: function () {
return this.get('firstName') + ' ' this.get('lastName');
}
}
});
In your view you can now do:
this.model.get('fullName'); // => Oscar Godson
Advanced Example:
A useful thing with getters is you can overwrite the basic lookups Backbone does with more advanced ones. A common example of this is to do basic associations.
Your group.json:
{
"id": "3",
"name": "Widget Group",
"members": [
{
"id": "1",
"permissions": 0
}
]
}
user.json
{
"firstName": "Oscar",
"lastName": "Godson",
"username": "oscargodson",
"id": "1"
}
Now you want to get the member's name in a view where the model is set to a Group model.
var myModel = Riblet.Model.extend({
getters: {
members: function () {
var members = this.attributes.members;
members.forEach(function (member, key) {
var userModel = app.collection.Users.findWhere({ id: member.id });
if (userModel) {
members[key] = _.extend(userModel.attributes, member);
}
});
return members;
}
}
});
In your view, instead of members returning an array of just the member's id
and permissions
you'd get this:
this.model.get('members')[0];
{
"firstName": "Oscar",
"lastName": "Godson",
"username": "oscargodson",
"id": "1",
"permissions": 0
}
Riblet.View
Overview
Riblet.View
provides basic life cycle, subview, and rendering features. It tries to not be too magical and requires you to be explicit in most cases. For example, while it may handle some of the "magic" in destroying all subviews or rendering from templates using getters
and templateHelpers
, you need to explicitly attach subviews and tell them where to attach to. You also need tell all views (including subviews) when to render. Nothing is rendered automagically.
The Life Cycle
Whenever you initialize a Riblet.View
it sets up a handful of life cycle methods for you to hook into. These are only fired when the corresponding method is fired. In other words, when you initialize a Riblet.View
it will only fire beforeInit
and afterInit
. Riblet does not guess when you want to render or destroy your components. You explicitly tell it to .render()
when you want it rendered or .destroy()
when you want it destroyed and so on.
The following before and after methods are currently supported and are fired whenever the matching method is called.
beforeInit
afterInit
beforeRender
afterRender
beforeDestroy
afterDestroy
beforeAddSubview
afterAddSubview
beforeDestroySubview
afterDestroySubview
initialize()
Riblet.View#initialize
does some minor setup for you. You can pass in optional attachTo
and attachMethod
options and it will take care of caching the selector and then later where and how to render the view.
As a reminder, initialize
fires when you initialize a view like var myView = new app.views.MyView();
.
Note: As with any Backbone or Riblet method, you can override this, but it's preferable to use beforeInit
or, more commonly, afterInit
.
Options
attachTo
- Where to inject the view at using theattachMethod
attachment method using a jQuery selector.attachMethod
(default:append
) - The jQuery method to use to attach the view at theattachTo
location. In pseudo code, if you set it tohtml
it'd call$(attachTo).html(templateHtml)
.
// By default app.views.Foo will always render to #app-container and
// replace all of the innerHTML with this view
app.views.Foo = Riblet.View.extend({
attachTo: '#app-container',
attachMethod: 'html'
});
// However, you could override this or require you give these options
// during initialization like:
var foo = new app.views.Foo({ attachTo: '#another-part-of-the-app' });
templateHelpers()
templateHelpers allow you to either override data or getters
with some other functionality to use specifically for your templates. Say you want to display a formatted date but your model's date
property is 1390378558475
. Simply create a date
templateHelper and do the conversion of that to January 22nd, 2014
in your templateHelper
. These are specifically meant for templating and don't affect model data lookups at all like getters do. This makes it nice for defining data presentation logic.
app.views.Foo = Riblet.View.extend({
templateHelpers: {
// Uses made up Date methods to give an example...
time: function () {
var d = new Date(this.model.get('date'));
return d.getMonthName() + d.getDayName() + ', ' + d.getFullYear();
}
}
});
templateData()
Overwrite this method if your view doesn't have a model associated with it, or the model data isn't the data you want to use for the view. By default, this method will check for this.model.attributes
and if that does not exist it will just return an empty object.
app.views.Foo = Riblet.View.extend({
fakeData: { foo: 'bar' }
// Use the fakeData object as the source of data for the view/templates
templateData: function () {
return this.fakeData;
}
});
render()
The .render()
method in Riblet does a bunch for you to make rendering easy and more intuitive than pure Backbone. The render process goes like this:
- First, as always, it calls
beforeRender
- It clones the
this.templateData()
(so it doesn't muck with the model data directly) - Goes through all the
getters
and applies them to the template data. This will overwrite anymodel.properties
that were being passed in from step 2. - Goes through all the
templateHelpers
and applies them to the template data. This will overwrite anymodel.properties
orgetters
that were being passed in from 2 or 3. - It sets the Backbone's
this.el
/this.$el
to the first element in your template rather than creating a newdiv
or forcing you to make one during your view setup like Backbone does normally. - Attaches the rendered template to the location you specified in the
attachTo
method using theattachMethod
given. - Sets the view to
rendered
- Calls
afterRender
Since this method does all of this it's advised you do not overwrite this, however, you can and nothing will break aside from the fact nothing will be rendered.
app.views.Foo = Riblet.View.extend({
afterInit: function () {
var bar = new app.views.Bar({ attachTo: '.bar' });
},
afterRender: function () {
bar.render();
}
});
isRendered()
Returns true
if .render()
has been called on the view. Returns false
if it has not.
app.views.Foo = Riblet.View.extend({
afterInit: function () {
var bar = new app.views.Bar({ attachTo: '.bar' });
// this.isRendered() => false
},
afterRender: function () {
bar.render();
// this.isRendered() => true
}
});
destroy()
The .destroy()
method will simply call remove on itself. If there are subviews attached to itself, it will call .destroy()
on them, which in turn, calls destroy on the subviews' subviews (and so on). It'll call beforeDestroy
before anything has happened and afterDestroy
after everything is removed from the DOM.
app.views.Foo = Riblet.View.extend({
events: {
'click .delete': 'itemDelete'
},
afterInit: function () {
var bar = new app.views.Bar({ attachTo: '.bar' });
bar.render();
},
itemDelete: function () {
bar.destroy();
}
});