Class: UWA.Class.Model

UWA/Class/Model. UWA.Class.Model

new UWA.Class.Model(attributes, options)

When creating an instance of a model, you can pass in the initial values of the attributes, which will be set on the model.

It is not recommended to override this init method for the construction of an instance of a model. You should rather implement the setup method, which will be invoked when the model is created.

In rare cases, if you're looking to get fancy, you may want to override this init constructor, which allows you to replace the actual constructor function for your model. In this case, please call first the parent init method in your overridden init method (see code example below)

If you pass a {collection: ...} in the options, the model gains a collection property that will be used to indicate which UWA.Class.Collection the model belongs to, and is used to help compute the model's url. This collection property is normally created automatically when you first add a model to a collection. Note that the reverse is not true, as passing this option to the constructor will not automatically add the model to the collection. Useful, sometimes.

If {parse: true} is passed as an option, the attributes will first be converted by the parse method before being set on the model.

Example
// A first example, provided that you have already defined a Book model :
var bookIRead = new Book({
    title: "One Thousand and One Nights",
    author: "Scheherazade"
});

// Another example where the init constructor function is overriden :
// (not really pertinent since what is done in init could have simply
// done in setup.)
var Library = UWA.Class.Model.extend({
    init: function() {
        this._parent.apply(this, arguments);
        this.books = new Books();
    },
    parse: function(data, options) {
        this.books.reset(data.books);
        return data.library;
    }
});
Parameters
Name Type Argument Description
attributes Object <optional>

attributes hash

options Object <optional>

options hash

Index

Members

<readonly> cid :String

A special property of models, the cid or client id is a unique identifier automatically generated and assigned to all instances of models when they're first created. Client ids are handy when the model has not yet been saved to the backend, and does not yet have its eventual true id, but already needs to be visible in the UI. Do not modify this property, only meant to be read.

Type
  • String

<readonly> collection :UWA.Class.Collection

A special property of models, collection is a reference to the UWA.Class.Collection your model belongs to, if any. This collection property is normally created automatically when you first add a model to a collection. Most of the time, you do not need to use this property, except maybe to compute your model's url. Do not modify this property, only meant to be read or set at construction time.

Type
  • UWA.Class.Collection

<readonly> validationError :Void

Error value returned by validate during the last failed validation of this model. It can consequently be of any type (string, object, ...) depending on what you choose to return in your implementation of validate. Do not modify this property, only meant to be read.

Type
  • Void

urlRoot :String|Function

Define this property if you're using a model outside of a collection.

Define this property if you're using a model outside of a collection, to enable the default url function to generate URLs based on the model id : "[urlRoot]/id" Normally, you won't need to define this. Note that urlRoot may also be a function.

Type
  • String | Function

defaults :String|Function

Define this property to specify the default attributes values hash for the model.

defaults hash (or function) can be used to specify the default attributes values for the model. When creating an instance of the model, any unspecified attributes will be set to their default value.

Note that defaults may also be a function.

Type
  • String | Function
Example
// Here is an example that show how you can make use of default
// attributes values as placeholders for a form or whatever :
var User = UWA.Class.Model.extend({
    validate: function(attributes) {
        // Here some validation code of the attributes
        // so that we make sure data is valid before save()...
    },

    defaults: {
        'name': 'Type your name', // ok, this is obvious :)
        'street': 'Type your street',
        'city': 'Type your city',
        'state': 'Type your state code',
        'zipCode': 'Type your zip code'
    }
});

// Another example :
// Whenever you want to inherit from and extend default attributes
// from a parent model, use this pattern of code :
var ChildModel = ParentModel.extend({
    defaults: function () {
        var parentDefaults = ParentModel.prototype.defaults;
        if (UWA.is(parentDefaults, 'function')) {
            parentDefaults = parentDefaults();
        }
        // In any case, clone what we got from the parent :
        parentDefaults = UWA.clone(parentDefaults, false);
        return UWA.extend(parentDefaults || {}, {
            'extra_attr' : 'nice to have!'
        });
    }
});

<readonly> id :String

A special property of instance of models, the id is an arbitrary string (integer id or UUID). If you set the id in the attributes hash (using set), it will be copied onto the model as this direct property id. Models can be retrieved by id from collections, and the id is used to generate model URLs by default.

Think of this property model.id as a shortcut for model.get(model.idAttribute).

Do not modify this property, only to be read.

Type
  • String

idAttribute :String

Override this property to transparently map from the unique identifying key in the backend to this model's id. By default, the model's unique identifier is stored under the 'id' attribute in the backend. If you are directly communicating with a backend that uses a different unique key, you may set a Model's idAttribute to transparently map from that key to id.

Type
  • String
Default Value:
  • 'id'
Example
// Say that we work with a backend that identifies users with
// the attribute/field 'user_ID', by specifying it in the
// idAttribute property, it's a no brainer for the client side
// code :
var UserModel = UWA.Class.Model.extend({
    idAttribute: 'user_ID'
});

var user1 = new UserModel({
    firstname: 'Colin',
    lastname: 'newman'
});

user1.save(null, {
    onComplete: function () {
        UWA.log(user1.id); // logs the id of user1,
                           // that is indeed the value in the id column
                           // 'user_ID' in the database...
    }
});

Methods

validate(attributes, options) → {Void}

Override this method (undefined by default) to implement your custom validation logic of the attributes.

This method is left undefined, and you're encouraged to override it with your custom validation logic, if you have any that can be performed in JavaScript. By default validate is called before save, but can also be called before set if {validate:true} is passed. The validate method is passed the model attributes, as well as the options from set or save. If the attributes are valid, don't return anything from validate; if they are invalid, return an error of your choosing. It can be as simple as a string error message to be displayed, or a complete error object that describes the error programmatically. If validate returns an error, save will not continue, and the model attributes will not be modified in the backend. Failed validations trigger an "onValidationFailure" event, and set the validationError property on the model with the value returned by this method.

"onValidationFailure" events are useful for providing coarse-grained error messages at the model or collection level.

Example
var Chapter = UWA.Class.Model.extend({
  validate: function(attrs, options) {
    if (attrs.end < attrs.start) {
      return "can't end before it starts";
    }
  }
});

var one = new Chapter({
  title : "Chapter One: The Beginning"
});

one.addEvent("onValidationFailure", function(model, error) {
  alert(model.get("title") + " " + error);
});

one.save({
  start: 15,
  end:   10
});
Parameters
Name Type Argument Description
attributes Object

the hash of attributes to validate

options Object <optional>

hash of options

Returns

If the attributes are valid, don't return anything from validate; if they are invalid, return an error of your choosing. It can be as simple as a string error message to be displayed, or a complete error object that describes the error programmatically.

Type
Void

clone() → {UWA.Class.Model}

Returns a new instance of the model with identical attributes.

Note that the cloned instance returned:

  • does not register any of the listeners registered by the original instance.
  • does not belong to any collection, even if the original instance belongs to a collection.

Note: When cloning a model, in addition to the remarks made above, keep in mind that attributes values that are objects are not deep copied. The example below demonstrates this. You can take care of this deep copy by yourself by overriding the init constructor, but be aware that performing a deep copy of attributes values with UWA.clone can become an expensive operation for very large, deep objects.

Example
var johnny, clone;

johnny = new UWA.Class.Model({
    'name': 'John Doe',
    'address': { // a better code would have split this address
                 // into 4 separate attributes...
        'street': '1st Street',
        'city': 'Austin',
        'state': 'TX',
        'zipCode': 78701
    }
});

clone = johnny.clone();
clone.set('name', 'John LookAlike');
clone.get('address').city = 'Dallas';

JSON.stringify(johnny);
// this returns :
// {"name":"John Doe",
//  "address":{
//     "street":"1st Street",
//     "city":"Dallas", // <-----
//     "state":"TX",
//     "zipCode":78701
// }}
//
// As you can see, John Doe's 'address' value has changed
// (city is now Dallas), but not its
// 'name' attribute value. This is the expected behavior.
// A way to change this normal behavior is to override your contructor,
// but be aware of the performance hit... :

MyModel = UWA.Class.Model.extend({
    init: function(attributes, options) {
        this._parent(UWA.clone(attributes), options); // a deep copy is performed.
    }
});
Returns
  • a new instance of the model with identical attributes.
Type
UWA.Class.Model

setup()

Override this method to initialize a newly created instance of model.

Do not directly call setup in your application code. It is internally used and consequently only meant to be overridden

Called when a new instance of a model is created, to initialize it. Its use is optional; however it is a good practice to use it, that is to say to implement it.

The default implementation does nothing.

It is passed the same arguments that were passed to the constructor {@link module:UWA/Class/Model.UWA.Class.Model#init|init} method.

Example
var Todo = UWA.Class.Model.extend({
    setup: function(){
        UWA.log('This model has been initialized.');
    }
});

var myTodo = new Todo();
// Logs: This model has been initialized.

sync(method, model, options) → {Object}

Override this method to implement, customize or fine-tune the manner in which models are persisted in or fetched from the backend.

This method is internally called by save, fetch and destroy, so you're not meant to call directly this sync method in your code.

By default, sync makes a RESTful Ajax request to the model's url, using UWA.Data.request API by default under the cover, unless you choose to use another Ajax implementation by using the option 'ajax' (see below). Consequently an error will be thrown if the model does not have an URL and no url is passed as an option in the options hash. The map from CRUD operation passed to HTTP verb used in Ajax request is the following :

  • a 'create' operation will launch a POST request.
  • a 'read' operation will launch a GET request.
  • an 'update' operation will launch a PUT request.
  • a 'patch' operation will launch a PATCH request.
  • a 'delete' operation will launch a DELETE request.

This default mapping can be easily overridden if an options.method is passed to sync :

model.save(null, {
    method: 'PUT' // this will be passed to sync method
                  // and eventually to Data.request
});

In most of the cases, this default implementation should suffice your needs (especially if you deal with a RESTful backend API), with some little tweaks. So before overriding sync on your model definition, think about you can achieve the same result just by passing the appropriate options and overriding the url method or urlRoot property.

Here is an example about how the default behavior of sync can be (indirectly by save) used to endorse/un-endorse a Post item in the backend :

var Post, p;

Post = UWA.Class.Model.extend({
    urlRoot: '/Posts',

    idAttribute: 'pid',

    save: function (attrs, options) {
        options = UWA.extend({}, options);
        if (!this.isNew()) {
            options.url += UWA.Utils.toQueryString(this.pick(this.idAttribute))
        } else {
            options.url = '/NewPost';
        }
        return this._parent(attrs, options);
    },

    toggleLikeStatus: function () {
        return this.save({
            endorsed: !this.get('endorsed')
        }, {
            url: this.urlRoot + '/endorse'
        });
    }
});

p = new Post();
p.save(); // this launches a HTTP POST request to '/NewPost'
p.set('pid', 'post1'); // to simulate in this example an identification returned by the backend
p.toggleLikeStatus(); // this launches a HTTP PUT request to '/Posts/endorse?pid=post1'

Now if you want to override this sync method for fine-tuning, your implementation must fulfill this specification :

  • it is passed the CRUD operation name ("create", "read", "patch", "update" or "delete"), the model in question and an hash of options passed by the callees (at least save, fetch and destroy but also any custom API of your own making calls to sync).
  • Regarding the options being passed, it is recommended to shallow clone this options hash in your implementation and possibly extend this clone. Then pass it to any underlying API you are using that takes options as input (such as UWA.Data.request)
  • options.onFailure (if provided) must be called (synchronously or asynchronously) upon failure of your backend to complete the operation passed as argument. The response of the backend must be passed to onFailure. Generally this is an error message.
  • options.onComplete (if provided) must be called (synchronously or asynchronously) after the successful completion in the backend of the operation passed as argument. The response of the backend must be passed to onComplete. This response must be parsable by your implementation of parse so that the model attributes are correctly updated automatically.
  • it must return a request object with a cancel() method to cancel the operation. If the operation is synchronous and consequently not cancellable, just return a dummy cancel() method on this object. If you use XmlHttpRequest, return it.

You never have to deal with setting/unsetting attributes of the model in your overridden implementation of sync. This is done by the callers save, fetch and destroy. See the implementation example below.

Some possible customizations could be:

  • Use setTimeout to batch rapid-fire updates into a single request.
  • Send up the models as XML instead of JSON.
  • Persist models via WebSockets instead of Ajax.
  • Persist models into Local Storage instead of Ajax.
  • etc.

Sync method internally calls UWA.Data.request (or any other implementation of Ajax if you chose to override it with options.ajax option). So you can pass any UWA.Data.request option directly as a sync option. For example, if you want to override the HTTP method used, you can do the following :

myModel.save({
    name: 'Edmond'
}, {
    method: 'POST'
});
Example
// Provided that we have a Safe object is capable to deal with find,
// findAll, insert, update and remove operations of models..., here is
// an example of a custom implementation of sync :

var MyPreciousModel;

MyPreciousModel = UWA.Class.Model.extend({

    sync: function (method, model, options) {
        var id, attrs, idAttrName, resp, errorMessage;

        if (method === 'create' || method === 'update' || method === 'patch') {
            attrs = model.toJSON(options);
        }
        id = model.id;
        idAttrName = model.idAttribute;

        try {
            switch (method) {
            case "read":
                resp = Core.is(id) ? this.safe.find(id) : this.safe.findAll();
                break;
            case "create":
                resp = this.safe.insert(attrs, idAttrName);
                break;
            case "update":
            case "patch":
                resp = this.safe.update(id, attrs);
                break;
            case "delete":
                resp = this.safe.remove(id);
                break;
            default:
                throw new Error(UWAString.format('Unsupported method "{0}"', method));
            }

        } catch (error) {
            errorMessage = error.message;
        }

        if (resp) {
            if (options && options.onComplete) {
                options.onComplete(resp);
            }
        } else {
            if (options && options.onFailure) {
                options.onFailure(errorMessage || UWAString.format('Model "{O}" not found in the safe', id));
            }
        }

        // return a dummy obj with a cancel() method since
        // operations in this.safe are synchronous and not
        // cancellable.
        return {
            cancel: function () {
                return;
            }
        };
    }
});

slushFund = new MyPreciousModel({
    id: 'bahamas_offshore'
});
slushFund.safe = new Safe(...);
slushFund.fetch();
slushFunc.set('owner', 'Norbert Damoff');
sluchFund.save();
Parameters
Name Type Argument Description
method Object

the CRUD operation to perform. Can be one of 'create', 'update', 'patch', 'delete' or 'read'

model Object

the model to be synchronized.

options Object <optional>

hash of options

Properties
Name Type Argument Default Description
ajax Function <optional>
null

Allow to specify another function for Ajax requests than UWA.Data.request. The function passed must have the same signature as UWA.Data.request and call the same onComplete and onFailure callbacks. See documentation of UWA.Data.request

Returns
  • An object that contains the cancel method to cancel the CRUD operation. (typically for example a UWA.Data.request). Note that the response headers are available available as options.responseHeaders
Type
Object

parse(resp, options) → {Object}

Override this method to transform the raw backend response into an hash of attributes for the model.

parse is called whenever a model's data is returned by the backend, in {@link module:UWA/Class/Model.UWA.Class.Model#fetch|fetch}, and save. The function is passed the raw response object, and should return the attributes hash to be set on the model.

The default implementation is a no-op, simply passing through the raw response from the backend, considering it is valid JSON data. Override this if you need to work with a preexisting APIs (which will be your case most of the time indeed), or see with the backend developers if they can better namespace their responses (which is an even better solution if you can!).

Notes:

  • You are not allowed to change the id of your model during parse . * Use idAttribute instead.
  • parse is an excellent place to extract and vivify incoming nested JSON into associated submodels.
Example
// Here is a small tip about how to deal with a backend sending responses
// in different formats for each C/R/U/D operation, which is a common use
// case.

MyModel = UWA.Class.Model.extend({
    // we override sync so that the C/R/U/D operation type is sent
    // to the APIs making calls to parse (namely save, destroy, fetch)
    // in the options hash :
    sync: function (method, model, options) {
        options.operation = method;
        return this._parent.apply(this, arguments);
    },

    // now parse will be passed the C/R/U/D operation type in options,
    // allowing you to deal with heterogenous response formats from
    // your ennoying backend :
    parse: function (response, options) {
        var attrs;
        switch (options.operation) {
            case 'create' :
                // parse the backend response to creation ...
                break;
            case 'delete' :
                // parse the backend response to deletion ...
                break;
            case ...
        }
        return attrs;
    }
});
Parameters
Name Type Description
resp Object

the raw response from the backend, to be parsed.

options Object

hash of options passed by the calling API (save, fetch, ...)

Returns
  • the attributes hash to be set on the model
Type
Object

url() → {String}

Override this method to return the relative or absolute URL of the model in the backend.

Normally you should not call url in your application code. It is internally used and consequently only meant to be overridden

url returns the relative or absolute (depending if your backend is on a different domain) URL where the model's resource would be located on the backend. If your models URLs logic is different, override this method with the correct logic.

The default implementation of url generates URLs of the form "[model.collection.url]/[model.id]", but you may override this url format by specifying an explicit urlRoot if the model's collection shouldn't be taken into account. See urlRoot property.

If urlRoot is not defined, this default implementation delegates to UWA.Class.Collection.url to generate the URL, so make sure that you have it defined, or a urlRoot property, if all models of this class share a common root URL. A model with an id of 101, stored in a UWA.Class.Collection with an url property of "/documents/7/notes", would have this URL: "/documents/7/notes/101"

Once again, if your models URLs logic is totally different, simply override and redefine this url method with your own logic.

Another way to specify URLs is to pass an {url: ...} option to the save, {@link module:UWA/Class/Model.UWA.Class.Model#fetch|fetch} or destroy API, this option will take precedence over this url method in the default implementation of sync.

Returns
  • The relative or absolute URL of the model's resource on the backend.
Type
String

set() → {Boolean}

Set a hash of attributes (one or many) on the model.

set sets a hash of attributes (one or many) on the model. If any of the attributes change the model's state, a "onChange" event will be triggered on the model. Change events for specific attributes are also triggered, and you can bind to those as well, for example: "onChange:title", and "onChange:content". You may also pass individual keys and values.

The signature handles both "key", value and {key: value} -style arguments. See example of code below.

set accepts as an optional last argument an hash of options, that will be passed to validate if defined and also attached to the onChange events sent. You can also pass the option {silent: true} to silently set attributes (in this case onChange events will not be fired).

Note that calling m.set('attr', undefined) if equivalent to calling m.unset('attr'), but prefer unset in your code.

Returns

true if succeeded to set the hash of attributes on the model. false if validation of attributes was required but failed.

Type
Boolean

unset(attr, options) → {Boolean}

Remove an attribute of the model.

unset removes an attribute by deleting it from the internal attributes hash. Fires a "onChange" event unless silent is passed as an option. If the attribute does not exist, nothing is performed.

Parameters
Name Type Argument Description
attr String

the name of the attribute to remove.

options Object <optional>

hash of options. If silent is passed as an option, no "onChange" event is fired.

Returns
  • true if succeeded to remove the attribute of the model
    • false if validation of attributes was required but failed.
Type
Boolean

clear(options) → {Boolean}

Removes all attributes from the model.

clear removes all attributes from the model, including the id attribute. Fires a "onChange" event unless { silent: true } is passed as an option.

Parameters
Name Type Argument Description
options Object <optional>

hash of options. If silent is passed as an option, no "onChange" event is fired.

Returns
  • true if succeeded to remove all attributes from the model.
    • false if validation of attributes was required but failed.
Type
Boolean

get(attr) → {Void}

Get the current value of an attribute from the model.

Example
var aNote = new Note({
    title:'a note'
});
aNote.get('title'); // returns 'a note'
Parameters
Name Type Description
attr String

the name of the attribute which value to be retrieved

Returns

The value of the attribute.

Type
Void

escape(attr) → {String}

Similar to get, but returns the HTML-escaped version of an attribute of this model. If you're interpolating data from the model into HTML, using escape to retrieve attributes will prevent XSS attacks.

Example
  var hacker = new UWA.Class.Model({
      name: ""
  });

  UWA.log(hacker.escape('name'));
Parameters
Name Type Description
attr String

the name of the attribute which value to escape.

Returns

the HTML-escaped version of attr

Type
String

has(attr) → {Boolean}

Returns true if the attribute is set to a non-null or non-undefined value.

Example
if (note.has("title")) {
    ...
}
Parameters
Name Type Description
attr String

the name of the attribute to check.

Returns

return true if the attribute is set to a non-null or non-undefined value, false otherwise.

Type
Boolean

keys() → {Array}

Returns the names of the model's attributes.

Example
var model = new UWA.Class.Model({
    one : 1,
    two : 2,
    three : 3
});
model.keys();
// returns ["one", "two", "three"]
Returns

an array containing the names of the model's attributes.

Type
Array

values() → {Array}

Return all of the values of the model's attributes.

Example
var model = new UWA.Class.Model({
    one : 1,
    two : 2,
    three : 3
});
model.values();
// returns [1, 2, 3]
Returns

an array containing the values of the model's attributes.

Type
Array

pairs() → {Array}

Returns the model's attributes into a list of [key, value] pairs.

Example
var model = new UWA.Class.Model({
    one : 1,
    two : 2,
    three : 3
});
model.pairs();
// returns [['one', 1], ['two', 2], ['three', 3]]
Returns

an array containing [key, value] pairs

Type
Array

toJSON(options) → {Object}

Return a shallow copy (see UWA.clone) of the model's attributes.

This can be used for persistence, serialization, or for augmentation before being sent to the backend. So you might need to override this method to suit your persistence/serialization needs...

Note that the name of this method is a bit confusing (since its does not actually returns a JSON string), but it conforms to , in that way that it will be called by JSON.stringify to determine the model's JSON representation.

Example
var artist = new UWA.Class.Model({
    firstName: "Wassily",
    lastName: "Kandinsky"
});

artist.set({birthday: "December 16, 1866"});

UWA.log(JSON.stringify(artist)); // JSON.stringify called the toJSON()
                                 // method to determine the model's
                                 // JSON representation
Parameters
Name Type Argument Description
options Object <optional>

hash of options passed by the calling API (save, fetch, ...)

Returns

a shallow copy of this model's attributes.

Type
Object

pick() → {Object}

Returns a copy of the model's attributes containing only the whitelisted attributes.

Example
var model = new UWA.Class.Model({
    name : 'moe',
    age: 50,
    userid : 'moe1'
});
model.pick('name', 'age');
// returns {name : 'moe', age : 50}

model.pick(['age', 'userid']);
// returns {age : 50, userid : 'moe1'}

model.pick(['name'], 'age', 'userid');
// returns {name : 'moe', age : 50, userid : 'moe1'}
Parameters
Type Argument Description
string <repeatable>

an attribute name or an array of attributes names

Returns

a copy of the whitelisted model's attributes

Type
Object

omit() → {Object}

Returns a copy of the model's attributes without the blacklisted attributes.

Example
var model = new UWA.Class.Model({
    name : 'moe',
    age: 50,
    userid : 'moe1'
});
model.omit('name', 'age');
// returns {userid : 'moe1'}

model.omit(['age', 'userid']);
// returns {name : 'moe'}

model.omit(['name'], 'age', 'userid');
// returns {}
Parameters
Type Argument Description
string <repeatable>

an attribute name or an array of attributes names

Returns

a copy of the model's attributes without the blacklisted attributes.

Type
Object

isNew() → {Boolean}

Returns true if the model has not yet been saved into the backend, false otherwise.

Has this model been saved to the backend yet? If the model does not yet have an id, it is considered to be new.

Returns

true if this model is new, false otherwise.

Type
Boolean

isValid(options) → {Boolean}

Run validate to check this model state.

Parameters
Name Type Description
options Object

Options hash.

Returns

true if this model state is valid, false otherwise.

Type
Boolean

hasChanged(attr) → {Boolean}

Returns true if the model has changed since the last "onChange" event.

hasChanged returns true if the model has changed since the last "onChange" event. This method is to be used during the course of a "onChange" event (that is to say called in your callback listening to changes), to check if some specific attribute has changed since the last "onChange" event. (see example below).

Example
var bookIRead = new Book({
    title:'Alice In Wonderland'
});
bookIRead.addEvent("onChange", function() {
    if (bookIRead.hasChanged("title")) {
        ...
    }
});
Parameters
Name Type Argument Description
attr String <optional>

If an attribute is passed, returns true if that specific attribute has changed.

Returns

true if if the model has changed since the last "onChange" event.

Type
Boolean

changedAttributes(diff) → {Object|false}

Retrieve a hash of only the model's attributes that have changed.

changedAttributes retrieve a hash of only the model's attributes that have changed, or false if there are none. This can be used to figure out which portions of a UI should be updated, or what calls need to be made to sync the changes to the backend. Note that unset attributes will be set to undefined in the returned hash. You can also pass an attributes object to diff against the model, determining if there would be a change. So, this method can be used during the course of a "onChange" event (that is to say called in your callback listening to changes), to detect the changes from the previous version of the object. But alternately, you can use this method outside the course of a "onChange" event, passing a diff hash to determine what would be the changes if this hash was passed to set.

Parameters
Name Type Argument Description
diff Object <optional>

an external attributes hash can be passed in, returning the attributes in that hash which differ from the model.

Returns
  • hash of only the model's attributes that have changed, or false if there are none.
Type
Object | false

previous(attribute) → {Void}

Get the previous value of a changed attribute.

previous returns the previous value of a changed attribute. This method is to be used during the course of a "onChange" event (that is to say called in your callback listening to changes), to get the previous value of a changed attribute. (see example below).

Example
var actress = new Model({
    name: "Norma Jeane Baker"
});
actress.addEvent("onChange:name", function (model, name) {
    alert("Changed name from " + actress.previous("name") + " to " + name);
});
actress.set({name : "Marilyn Monroe"});
Parameters
Name Type Description
attribute String

the name of the attribute

Returns

previous value of the changed attribute.

Type
Void

previousAttributes() → {Object}

Return a copy of the model's previous attributes.

previousAttributes returns a copy of the model's previous attributes. Useful for getting a diff between versions of a model. Also useful for getting back to a valid state after a backend-side error occurs during save or update. This allows for example to immediately update an UI when the user makes a change to the model, without waiting for the response of the call made to the backend to persist the changes. If the backend rejects the request or executes it differently, the client can be restored to its previous valid state.

This method is to be used during the course of a "onChange" event (that is to say called in your callback listening to changes), to get a copy of the model's previous attributes.

Returns

a copy of the model's previous attributes.

Type
Object

save() → {Object|false}

Save the model in the backend (e.g CREATE/UPDATE/PATCH).

save saves the model in the backend by delegating to sync and eventually (in the default implementation of sync) to sync.

The attributes hash (as in set) should contain the attributes you'd like to change — keys that aren't mentioned won't be altered — but a complete representation of the resource will be sent to the backend. (This is just a shortcut version of a set + save calls sequence) As with set, you may pass individual keys and values instead of a hash. If the model has a validate method, and validation fails, the model will not be saved. If the model isNew, the save will be a "create" (HTTP POST in default sync implementation), if the model already exists in the backend, the save will be an "update" (HTTP PUT in default sync implementation).

If instead, you'd only like the changed attributes to be sent to the backend, call model.save(attrs, {patch: true}). A 'patch' operation is launched. In the default sync implementation, that 'patch' operation is implemented with an HTTP PATCH request sent to the backend with just the attributes passed to {@link module:UWA/Class/Model.UWA.Class.Model#save|save}, not the whole hash of this model's attributes. (See RFC 6902)

Calling {@link module:UWA/Class/Model.UWA.Class.Model#save|save} with new attributes will cause a "onChange" event to be immediately fired and an "onSync" event after the backend has successfully performed the CREATE/UPDATE/PATCH operation or an 'onError' event if the backend failed to perform the operation. With the default sync implementation, an "onRequest" event is fired as the XHR begins to go to the backend.

Pass {wait: true} if you'd like to wait for the backend response before setting the new attributes on the model.

Another option is to immediately alter the model attributes in the client (these changes will consequently be immediately reflected in the UI) without waiting for the backend response (latency compensation aka reactive optimistic UI), but revert the model attributes to their previous values if the backend fails to save the model (see previousAttributes method).

Save accepts onComplete and onFailure callbacks in the options hash, which are both passed (model, response, options) as arguments.

Note: The signature handles both "key", value and {key: value} -style arguments. See example of code below.

Example
var Cake;

Cake = Model.extend({
    defaults: {
        type: 'plain',
        nuts: false
    },
    urlRoot: 'cake'
});

Cake.implement(Debug);

myCake = new Cake();

// save called with a hash of attribute names and values :
myCake.save({
    type: 'coconut',
    nuts: true
}, {
    wait:true,
    onComplete: function(model, response) {
        model.log('Successfully saved!');
    },
    onFailure: function(model, error) {
        model.log(model.toJSON());
        model.log('error.responseText');
    }
});

// save called with a key, value -style arguments :
myCake.save('price', 99.99, {
    wait: true
});
Returns

If validation is successful, returns an object that contains the cancel method, to cancel the operation if needed. If validation failed, returns false.

Type
Object | false

fetch(options) → {Object}

(READ) Fetches the attributes for this model from the backend.

{@link module:UWA/Class/Model.UWA.Class.Model#fetch|fetch} resets the model's state from the backend by delegating to sync. Returns a request/operation object that contains the cancel method. Useful if the model has never been populated with data, or if you would like to ensure that you have the latest backend state. A "onChange" event will be triggered if the backend's state differs from the current attributes. With the default sync implementation, a "onRequest" event will be trigerred as the XHR begins to go to the backend. An "onSync" event is triggered if the backend successfully performed the READ operation. An 'onError' event is fired if the backend failed to perform the operation.

{@link module:UWA/Class/Model.UWA.Class.Model#fetch|fetch} accepts onComplete and onFailure callbacks in the options hash, which are both passed (model, response, options) as arguments.

Example
// Poll every 10 seconds to keep the channel model up-to-date.
window.setInterval(function () {
    channel.fetch();
}, 10000);
Parameters
Name Type Description
options Object

Options hash

Returns

An object that contains the cancel method, allowing to cancel the operation made into the backend.

Type
Object

destroy(options) → {Object}

Destroys the model in the backend.

destroy destroys the model in the backend by delegating a 'delete' operation to sync.

The default implementation of sync makes an HTTP DELETE request to the backend to implement this 'delete' operation.

destroy accepts onComplete and onFailure callbacks in the options hash, which are both passed (model, response, options) as arguments.

destroy triggers a "onDestroy" event on the model, which will bubble up through any collections that contain it (that will themselves emit 'onRemove' events) and an "onSync" event it the backend successfully performs the model's deletion or an 'onError' event if the backend failed to perform the 'delete' operation. With the default {@link module:UWA/Class/Model.UWA.Class.Model#sync|sync} implementation, an "onRequest" event is fired as it begins the XHR to the backend.

Pass {wait: true} if you'd like to wait for the backend to respond before removing the model from the collection.

Parameters
Name Type Description
options Object

Options hash.

Returns

An object that contains the cancel method or false if the model isNew

Type
Object