Backbone with modifications. Adds heirarchy to Views, derived properties on Models and general utility.
Bam is automatically tested in IE9-10, and the latest versions of other browsers. It has been used in production in IE7, IE8 and many previous versions of other browsers.
Bam is an extension to Backbone. It extends the core Backbone classes with common utility functions and a some new functionality:
Over time, Bam's philosophy has changed from all extensions you may want to only those extensions that can't be achieved as standalone modules.
Beyond the new functionality and utility methods added to the classes they still function the same as the original Backbone classes. With the exception of the Router.
You can install from npm and use whatever commonjs build system you'd like to import it. Browserify is recommended because it requires
npm install bamjs
If you're not using npm a UMD module is available.
The view heirarchy allows traversal and event bubbling. A view can be added as a parent or a child.
var one =var two =view1setParentview2
var one =var two =view2addChildview1
Adding a child view will automatically set the child's parent view to yourself. Similarly, setting a parent view will automatically add yourself as a child of the parent.
You can construct a view with a parent:
var one =var two = parent: one
Also with children:
var two =var one = children: two
You can access parents and children with simple traversal functions.
onehasParent //Boolean: If you have a parentonegetParent //View: Your parentonehasChildren //Boolean: If you have any childrenonegetChildren //Array: All your childrenonehasChildtwo //Boolean: if any child is the viewonehasDescendanttwo //Boolean: if any child or child's child is the viewtworoot //View: your root view, or youself if you are the root view
To help with cleanup,
view.remove() will do a depth-first traversal calling remove on all children and grandchildren before finally removing itself.
Events triggered on one view bubble through each parent view before finally stopping on root.
var root =var child = parent: rootchildtrigger'foo' // 'foo' will also trigger on the parent view.
If you have concerns about event names clashing you can add the namespace property to your views either at construction with the options object or at definition with the View prototype.
This helps reduce the need to propagate events manually, and also gives you a common event bus for all views within a view tree. Even if two views belong on completely separate branches, they share the same root element.
Models can define derived values. Derived values are model properties that exist as a result of passing other values through a function. They are accessed with the get function like other Model attributes and trigger change events when their dependencies change.
model.derived to define derived values.
var MyModel = Modelextendderived:'foo':deps: 'bar' 'baz'return 'bar' + ', ' + 'baz' + '!'
Derived values cannot be set, only accessed. All dependencies are passed in-order to the value function per calculation and if any of the are changed, a change event will also be fired for the derived value.
Using the definition from before:
var m =bar: 'Hello'baz: 'world'mget'foo' //'Hello, world!'mon'change:foo'console.logvaluemset'baz' 'developer' //
baz is set to
change:foo event fires and
'Hello, developer!' will be logged to the console.
When setting values Bam Models will first check if the key exists in a defined casts object. If it does it'll apply the appropriate cast to the value before setting it.
var MyModel = Modelextendcast:foo: 'string'bar: 'int'baz: 'date'var m =foo: truebar: 4.11baz: '2012-01-01'mget'foo' //'true'mget'bar' //4mget'baz' //Sun Jan 01 2012 11:00:00 GMT+1100 (EST)
Bam provides the following defaults:
'boolean'. You can provide your own by setting the cast value to a function which takes a value and returns a new value.
var MyModel = Modelextendcast:return 42
In this example, any value that's set as
'foo' will be turned into the Number 42.
The goals for the router were to:
Because this model doesn't lend itself to the style of callbacks you normally get in Backbone, i.e., parameters are applied to the callback in-order Bam will instead call your router callbacks with a request object as the single argument.
'foo' with definition
var MyRouter = Routerextendthisroute':foo(/:bar)/:baz' 'foo' thisfooBar// Do something with req
and it was matched by the fragment
one/two?name=bam then you'd get the following request object as the callback to
route: ':foo(/:bar)/:baz'fragment: 'one/two?name=bam'name: 'foo'values: 'one' 'two'params:foo: 'one'bar: nullbaz: 'two'query:name: 'bam'
route: The route that was matched.
fragment: The fragment that was matched to the route.
name: The name of the route.
values: The values of the params in the order they appeared in the fragment.
params: The route params that were matched as
key: valuepairs of the object. If an optional param wasn't matched, it will be
query: The query string parsed to an object. If no query was specified then it will be an empty object.
The request object will be passed to the route callback as its only argument.
Bam routes have a method called
reverse which takes a route name and a request-like object and will return a fragment that would match that route and request object.
var MyRouter = Routerextendthisroute':foo(/:bar)/:baz' 'foo' thisfooBar// Do something with reqvar r =rreverse'foo'params:foo: 'one'baz: 'two'query:name: 'bam'// 'one/two?name=bam'
If you use regex routes, the names of params will be their indexes in the values array.
You cannot reverse regex routes.
In normal backbone Routers you can define routes as a property of your Router class. Because the name is important for reverse routing this has been disabled in Bam Routers.
See the wiki for the full API.