Composer.js

Utilities

Composer has a number of utilities that are used throughout the framework, but can also be used by your app as well.

Composer.sync :: function(method, model, options)

Composer’s syncing function. It provides a central location for models and collections to grab and post data to your servers/browser storage/etc. By default, it does nothing and should be overridden by you.

method is one of “create”, “read”, “update”, “delete”. model is the model the sync function is being called on. options is the options object passed to the model/collection’s save, fetch, destroy function.

Note that options also has two functions in it: success and error. success should be called when the call to your API finishes, the only argument being the data returned from the API. error should be called if any errors happen (first arg is the error, second is the XHR object).

Note that you can also provide syncing functions on a per-model or per-collection basis by setting the .sync parameter in that object (ie mymodel.sync = my_sync_function;.

Sync function example:

Composer.sync = function(method, model, options)
{
    var http_method = 'get';
    switch(method)
    {
    case 'read': http_method = 'GET'; break;
    case 'create': http_method = 'POST'; break;
    case 'update': http_method = 'PUT'; break;
    case 'delete': http_method = 'DELETE'; break;
    }

    if(['POST', 'PUT'].indexOf(http_method) >= 0)
    {
        var data = model.toJSON();
    }
    else
    {
        var data = {};
    }

    FictionalApp.API.call(http_method, model.get_url(), data, {
        success: options.success,
        error: options.error
    });
};

Composer.set_sync :: function(syncfn)

A helper function to set the Composer.sync function. Not super useful in a browser setting, but helpful if running Composer in Node.js.

Composer.set_sync(function(method, model, options) {
    // ...
});

Composer.cid :: function()

A function that generates client-ids for every object instantiated by Composer. This function can be replaced with your own.

// assign our own CID generating function
Composer.cid = (function() {
    var x = 0;
    return function() {
        x++;
        return 'z'+x;
    }
})();
// test our wonderful new CID generator
alert('CID: '+ new Composer.Model().cid());

Composer.eq :: function(a, b)

Determines if two objects are equal. Does a deep-inspection of objects and arrays.

alert('eq? ' + Composer.eq(
    {name: 'andrew', friends: ['larry', 'curly', 'moe']},
    {name: 'andrew', friends: ['larry', 'curly', 'moe']}
));
alert('eq? ' + Composer.eq(
    {name: 'andrew', friends: ['larry', 'curly', 'moezzz']},
    {name: 'andrew', friends: ['larry', 'curly', 'moe']}
));

Composer.merge_extend :: function(class, array_of_property_names)

See Composer.merge_extend in the class docs.

Composer.array

A collection of array utilities.

erase :: function(array, item)

Erase all instances of an item from an array.

var arr = [1,2,3];
Composer.array.erase(arr, 2);
alert('Result: '+ JSON.stringify(arr));

is :: function(obj)

Determine if obj is an Array object. This can usually be done with instanceof, however if you get an array from another window/iframe, the test will crash and burn. Composer.array.is has some provisions to work around this.

alert('Is array: '+ Composer.array.is([1,2,3]) + ' / ' + Composer.array.is({name: 'larry'}));

Composer.object

A collection of object utilities.

each :: function(obj, fn, bind)

Call fn for each key/value pair on obj (optionally binding bind to fn’s scope).

Composer.object.each({name: 'andrew', age: 27}, function(val, key) {
    console.log('k/v', key, val);
});

clone :: function(obj, options)

Returns a clone of the given object obj (shallow by default)`.

options can contain the following items:

  • deep - if true, performs a deep clone
var clone = Composer.object.clone({horses: 'goodbye'});
var clone2 = Composer.object.clone({name: 'buffalow bill', listens: {horses: 'goodbye'}}, {deep: true});

merge :: function(to, …)

Merge a number of objects into to, objects being listed later having preference.

var obj = {};
Composer.object.merge(obj, {name: 'fisty'}, {age: 69});
alert('Obj: ' + JSON.stringify(obj));

set :: function(object, key, value)

Recursively set a value into an object:

var user = {};
Composer.object.set(user, 'location.city', 'santa cruz');
alert(JSON.stringify(user));

get :: function(object, key)

Recursively get a value from an object:

var city = {location: {city: 'santa cruz'}};
Composer.object.get(user, 'location.city');
alert(city);

Composer.promisify :: function(options)

New in version 1.0.6, this function replaces the following methods with promise-ready versions:

Instead of accepting options.success and options.error, these functions will now return promises (assuming you have included a promise library in the page).

This changes the interface for these functions a bit, but once you get the hang of it, you can use the same technique for all of them.

options can contain the following items:

  • warn - if true, will fire a warning when trying to use callbacks (ie success or error) with a promisified function. This helps to track down places where your app used callbacks previously but no longer uses them.

Here’s an example:

my_app.show_loading();
var dog = new Composer.Model({id: 17});
dog.fetch({
    success: function(model) {
        console.log('success! ', model.get('name'));
        my_app.hide_loading();
    },
    error: function(model, err) {
        console.error('oh no: ', err);
        my_app.hide_loading();
    }
});

…and now after calling promisify:

my_app.show_loading();
var dog = new Composer.Model({id: 17});
dog.fetch()
    .then(function(model) {
        console.log('success! ', model.get('name'));
    })
    .catch(function(err) {
        console.error('oh no: ', err);
    })
    .finally(function() {
        my_app.hide_loading();
    });

The syntax difference is negligable, however promises offer a lot of power when it comes to stringing together async operations and especially handling errors.

Note that your Composer.sync function will not need to change once you call promisify: it still makes use of the options.success and options.error callbacks in the same way.

Note on promisify usage

If you are going to use promisify(), you need to call it before you define your app’s Models/Collections, otherwise their prototypes will extend the old (non-promisified) Composer.Model/Collection objects (and won’t return promises).

Composer.find_parent :: function(selector, element)

Although this is a global utility function, it exists as part of the Controller/Adapter library and is documented there.