promise based, typed attributes, nested models and collections
npm install promised-models * promise based
* typed attributes
* nested models and collections
* async calculations and validation
$npm install --save promised-models
``js
var Model = require('promises-models'),
FashionModel = new Model.inherit({
attributes: {
name: Model.attributeTypes.String
}
}),
model = new FashionModel({
name: 'Kate'
});
model.get('name'); // 'Kate'
`
#### inherit Model.inherit(properties, [classPorperties])
Creates you own model class by extending Model. You can define attributes, instance/class method and properties. Inheritance is built over inherit.
`js`
var CountedModels = Model.inherit({
__constructor: function () {
this.__base.apply(this, arguments); //super
this.attributes.index.set(this.__self._count); //static properties
this.__self._count ++;
},
getIndex: function () {
return this.get('index');
}
}, {
_count: 0,
getCount: function () {
return this._count;
}
});
#### attributeTypes Model.attributeTypes
Namespace for predefined types of attributes. Supported types:
* StringNumber
* Boolean
* List
* — for storing arraysModel
* — for nested modelsModelsList
* — for nested collectionsObject
* — serializable objects
You can extend default attribute types or create your own
`js`
var DateAttribute = Model.attributeTypes.Number.inherit({
//..
}),
FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String,
birthDate: DateAttribute
}
});
Note: models.attributes will be replaced in constructor with attribute instances.
`js`
var model = new FashionModel();
model.attributes.birthDate instanceof DateAttribute; //true
#### set model.set(attributeName, value)
Set current value of attribute.
`js`
var model = new FashionModel();
model.set('name', 'Kate');
model.attributes.name.set('Kate');
model.set({
name: 'Kate',
birthDate: new Date(1974, 1, 16)
});
Note: setting null is equivalent to call .unset()
#### get model.get(attributeName)
Get current value of attribute.
`js`
var model = new FashionModel({
name: 'Kate',
birthDate: new Date(1974, 1, 16)
})
model.get('name'); //Kate
model.attributes.name.get(); //Kate
model.get('some'); //throws error as unknown attribute
#### toJSON model.toJSON()
Return shallow copy of model data.
Note: You can create internal attributes, which wouldn't be included to returned object.
`js`
var FashionModel = new Model.inherit({
attributes: {
name: Model.attributeTypes.String.inherit({
internal: true;
}),
sename: Model.attributeTypes.String.inherit({
internal: true;
}),
fullName: Model.attributeTypes.String
}
}),
model = new FashionModel({
name: 'Kate',
sename: 'Moss',
fullName: 'Kate Moss'
});
model.toJSON(); // {fullName: 'Kate Moss'}
model.get('name'); // Kate
Note: Returned object supposed to be serializable via JSON.parse(). Due to this reason NaN and Infinity are serialized in this way:
``
NaN -> null
Infinity -> 'Infinity'
#### isChanged model.isChanged([branch])
Has model changed since init or last commit/save/fetch.
`js`
var FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String,
weight: Model.attributeTypes.Number.inherit({
default: 50
})
}
}),
model = new FashionModel({
name: 'Kate',
weight: 55
});
model.isChanged(); //false
model.set('weight', 56);
model.isChanged(); //true
#### commit model.commit([branch])
Cache current model state
`js`
var model = new FashionModel();
model.set({
name: 'Kate',
weight: 55
});
model.isChanged();//true
model.commit();
model.isChanged();//false
#### revert model.revert([branch])
Revert model state to last cashed one
`js`
var model = new FashionModel({
name: 'Kate',
weight: 55
});
model.set('weight', 56);
model.revert();
model.get('weight'); //55
model.isChanged(); //false
Note: You can create your own cache by passing branch param.
`js`
var RENDERED = 'RENDERED';
model.on('change', function () {
if (model.isChanged(RENDERED)) {
View.render();
model.commit(RENDERED);
}
});
#### on model.on([attributes], events, cb, [ctx])
Add event handler for one or multiple model events.
List of events:
* change – some of attributes have been changedchange:attributeName
* – attributeName have been changeddestruct
* – model was destructedcalculate
* – async calculations started
`js`
model.on('change', this.changeHandler, this)
.on('change:weight change:name', this.changeHandler, this);
#### un model.un([attributes], events, cb, [ctx])
Unsubscribe event handler from events.
`js
//subscribe
model.on('weight name', 'change', this.changeHandler, this);
//unsubscribe
model.un('change:weight change:name', this.changeHandler, this);
`
#### destruct model.destruct()
Remove all events handlers from model and removes model from collections
#### isSet model.isSet(attributeName)
Returns true if attribute was set via constructor or set
`js`
var model = new FashionModel();
model.isSet('name'); //false
model.set('name', 'Kate');
model.isSet('name'); //true
#### unset model.unset(attributeName)
Set attribute to default value and model.isSet() === 'false'
`js`
var model = new FashionModel();
model.set('name', 'Kate');
model.unset('name');
model.isSet('name'); //false
model.get('name'); //empty string (default value)
#### validate model.validate()
Validate model attributes.
`js
var FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String.inherit({
validate: function () {
return $.get('/validateName', {
name: this.get()
}).then(function () {
return true; //valid
}, function () {
return false; //invalid
});
}
})
}
}),
model = new FashionModel();
model.validate().fail(function (err) {
if (err instanceof Model.ValidationError) {
console.log('Invalid attributes:' + err.attributes.join());
} else {
return err;
}
}).done();
`
#### ready model.ready()
Fulfils when all calculations over model finished.
`js
var FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String,
ratingIndex: Model.attributeTypes.Number.inherit({
calculate: function () {
return $.get('/rating', {
annualFee: this.model.get('annualFee')
});
}
}),
annualFee: Model.attributeTypes.Number
}
}),
model = new FashionModel();
model.set('annualFee', 1000000);
model.ready().then(function () {
model.get('ratingIndex');
}).done();
`
#### fetch model.fetch()
Fetch data associated with model from storage.
`js
var FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String
},
storage: Model.Storage.inherit({
find: function (model) {
return $.get('/models', {
id: model.id
});
}
})
}),
model = new FashionModel(id);
model.fetch().then(function () {
model.get('name');
}).done();
`
#### save model.save()
`js
var FashionModel = Model.inherit({
attributes: {
name: Model.attributeTypes.String,
weight: Model.attributeTypes.Number
},
storage: Model.Storage.inherit({
insert: function (model) {
return $.post('/models', model.toJSON()).then(function (result) {
return result.id;
});
},
update: function (model) {
return $.put('/models', model.toJSON());
}
})
}),
model = new FashionModel();
model.set({
name: 'Kate',
weight: 55
});
model.save().then(function () { //create
model.id; //storage id
model.set('weight', 56);
return model.save(); //update
}).done()
`
#### remove model.remove()
Removes model from storage.
* model.isNew()model.isReady()
* model.trigger(event)
* model.calculate()
* model.CHANGE_BRANCH
* model.CALCULATIONS_BRANCH
*
These methods provided for advanced model extending. Consult source for details.
#### Storage Model.Storage
Abstract class for model storage
`js`
var FashionModel = Model.inherit({
attributes: {
//..
},
storage: Model.Storage.inherit({
//..
})
});
#### Class storage Model.storage
Storage class
`js`
var SuperModel = FashionModel.inherit({
storage: FashionModel.storage.inherit({ //extend storage from FashionModel
//..
})
});
#### Attribute Model.Attribute
Base class for model attribute
`js`
var CustomAttribute = Model.attribute.inherit({
//..
})
#### Class attributes Model.attributes
Model class attributes
`js`
var SuperModel = FashionModel.inherit({
attributes: {
name: FashionModel.attributes.name,
weight: FashionModel.attributes.weight.inherit({
default: 50
})
}
});
#### Model.on([attributes], events, cb, [ctx])
Bind event on all models of class
`js`
FashionModel.on('change', this.changeHandler, this);
#### Model.un([attributes], events, cb, [ctx])
Unbind event on all models of class
Array like object returned for fields types List and ModelsList
`
var Podium = Model.inherit({
attributes: {
models: Model.attributeTypes.ModelsList(FashionModel)
}
}),
podium = new Podium(data),
list = podium.get('models'), //instanceof List
model = list.get(0); //instanceof Model
`
#### Mutating methods
List inerits Array mutating methods: pop, push, reverse, shift, sort, splice, unshift
``
podium.get('models').push(new FashionModel());
#### list.get(index)
Get list item by index
``
podium.get('models').get(0);// instanceof Model
#### list.length()
Returns length of list
#### list.toArray()
Returns shallow copy of Array, wich stores List items
``
podium.get('models').forEach(function (model) {
model; // instanceof Model
});
#### ValidationError Model.ValidationError`
Error class for validation fail report
$ npm test