Skip to content

Models and Collections

Jason Strimpel edited this page Aug 20, 2014 · 6 revisions

Lazo models and collections extend Backbone.Model and Backbone.Collection. Lazo also has the concept of a proxy layer – one for the client and one for the server. On the client it leverages a custom Backbone.sync that sends all requests through a tunnel end point on the Lazo application server. On the server it either forwards the request directly to an service end point or if a Lazo syncher exists for the model, collection Lazo forwards the request to the Lazo syncher.

"Model" will be used to refer to both models and collections from this point forward.

// example model; the Lazo Collection module id is lazoCollection
define(['lazoModel'], function (LazoModel) {

    'use strict';

    var host = 'http://someservicehost.com/'

    return LazoModel.extend({

        url: function () {
            var params = this.params;
            return host + params.department + '/' + params.page + '/';
        }

    });

});

Directory Structure

The models directory contains a sub directory for each model. Underneath each model directory there is an optional server directory.

|- models
    |- model_name
        model.js or collection.js (optional if syncher exists) 
        |- server (optional if model.js exists)
           syncher.js         

Model Parameters

Model instances are identified by their parameters. If a model is loaded with the same parameters hash as another model that was already loaded then a pointer to the loaded model is returned.

Once a model has been loaded the parameters can be set directly on the model.

// set a single parameter
this.ctx.models.someModel.params.someParameter = 1;

// reset all parameters
this.ctx.models.someModel.params = {
    someParameter: 1
};

Loading a Model

Models are loaded using the base Lazo controller methods loadModel and loadCollection. These methods proxy to their corresponding LAZO.app methods automatically passing the calling controller context. The model data will be fetched by default when the model is loaded unless the option fetch with a value of “false” is passed.

define(['lazoCtl'], function (LazoController) {

    'use strict';

    return LazoController.extend({

        index: function (options) {
            var params = this.ctx.params;

            // load items collections
            this.loadCollection('items', {
                // pass controller context parameters to collection
                params: _.pick(params, ['page', 'department']),
                success: function (items) {
                    // add a reference to the controller context
                    self.ctx.collections.items = items;
                    // call index options.success
                    options.success('index');
                },
                error: options.error
            });
        }

    });

});

Synchers

Sometimes it is not always best to go directly to a service end point. In some cases data may need to be aggregated to reduce the number of network calls for a page request, restructuring of data may need to occur, or some other data related logic might need to happen. Instead of disbursing this logic throughout the application Lazo provides a mechanism for encapsulating it, a Lazo syncher. Syncher CRUD methods map directly to model CRUD methods, so that when a model CRUD operation is called it executes the corresponding syncher method returning the data from the syncher back to the model.

Lazo synchers are only executed on the server.

define(['lazoSyncher', 'request'], function (LazoSyncher, request) {

    'use strict';

    var host = 'http://someservicehost.com/';
    var cache = {
        // persist data in a cache
        set: funciton (key, value) {
            return {};
        },
        // lookup data in a cache
        get: function (key) {
            return {};
        }
    };

    function formatErrResp(err, resp, body) {
        return {}; // format error response
    }

    return LazoSyncher.extend({

        fetch: function (options) {
            var params = options.params;
            var uri = host + params.department + '/' + params.page + '/';
            var data;

            // check if data is in cache
            if (data = cache.get(uri)) {
                return options.success(data);
            }

            // data was not in cache; fetch from service endpoint
            request({ uri: uri }, function (err, resp, body) {
                if (err) {
                    return options.error(formatErrResp(err, resp, body))
                }

                // parse response body
                data = JSON.parse(body);
                // cache data for future requests
                cache.set(uri, data);
                // pass data back to model
                options.success(data);
            });
        }

    });

});

Creating a Model

In addition to being loaded models can be created and automatically persisted at runtime using the controller method, createModel, which calls the LAZO.app, counterpart automatically passing the calling controller context.

define(['lazoView'], function (LazoView) {

    'use strict';

    return LazoView.extend({

        events: {
            'click button': 'save'
        },

        indicator: function (show) {
            // show, hide an UI indicator
        },

        alert: function (type, message) {
            // notify user of results
        },

        save: function (e) {
            var name = this.$('[name="user"]');
            var password = this.$('[name="password"]');
            var self = this;

            e.preventDefault();

            this.indicator(true);
            // create a user model in response
            // to a save button click
            this.ctl.createModel('user', {
                name: name
                password: password
            }, {
                success: function () {
                    self.indicator(false);
                    self.alert('success', 'user added!');
                },
                error: function () {
                    self.indicator(false);
                    self.alert('error', 'oopsy!');
                }
            });
        }

    });

});
Clone this wiki locally