Gallery

The Gallery is deprecated. No new Gallery components may be submitted, and modifying existing components is disabled. For more information please read the Gallery Deprecation blog post. This is a static snapshot of the Gallery for archive purposes.

Satyam

YUI Contributor

The existing Y.Model is not suitable for usage with existing databases. This version, which unfortunately is incompatible with the original, supports:

Multiple-field primary keys

keeps track of the values as loaded from the server so updates can be done safely by using the original values in the WHERE clause of the UPDATE statement, to ensure the record has not been modified by another user while being edited on screen

Data fields and meta-data are separate so there are no limitations on the name of the fields due to conflicts in between record status attributes and record data attributes.

New records are properly signaled by the isNew attribute, which makes no assumption about new records having no primary key set.

Additionally:

Undo functionality is split into a separate extension. Two of them are provided as samples.

Field values can be set without declaring them previously (much as the YUI2 Record did)

A single 'change' event is fired for changes in any field. The field being changed is identified in the event facade. There is no need to set listeners on each data field separately.

The change can be prevented by the before event listener and/or the value changed.

Finally, the included multiple-record extension allows holding instances of the same type of record in a single model, to keep it sorted and search through it.

Code Sample

YUI({//Last Gallery Build of this module
gallery:'gallery-2012.09.05-20-01'}).use('gallery-md-model','json',function(Y){var MyModel = Y.Base.create('my-model',
Y.GalleryModel,[],{
sync:function(action, options, callback){switch(action){case'read':
callback(null, Y.merge({fieldOne:1, fieldTwo:2}, options));break;case'create':case'update':case'delete':
callback(null);break;default:
callback('operation not allowed');break;}},// Method toJSON() is originally set to call method getValues()// Having toJSON() separate from getValues() allows redefining toJSON()// without messing up getValues()
toJSON:function(){return{// getPKValues() (PK: primary key) returns an object with the values for the primary key(s)
keys:this.getPKValues(),// getChangeValues() returns an object with the previous and new values // for all fields changed since last synched with the remote source
values:this.getChangedValues()};}},{
ATTRS:{// primaryKeys is now an attribute and can take multiple fields// If only one, a single string (not an array) can be provided
primaryKeys:{
value:['primaryKey1','primaryKey2']}}});var myModel =new MyModel();// isNew and isModified are now attributes
console.log('new model', myModel.get('isNew'), myModel.get('isModified'));// should show: "new model true false"
myModel.load({primaryKey1:12, primaryKey2:34},function(err, response){
console.log('loaded model', myModel.get('isNew'), myModel.get('isModified'));// should show: "loaded model false false"// Field values are read/set via getValue/setValue methods
console.log('fieldOne: ', myModel.getValue('fieldOne'));// should show: "fieldOne: 1"
myModel.setValue('fieldOne',3);// You can query the status of individual fields or the whole record
console.log('fieldOne status: ', myModel.get('isNew.fieldOne'),myModel.get('isModified.fieldOne'));// should show: "fieldOne status: false true"
console.log('fieldTwo status: ', myModel.get('isNew.fieldTwo'),myModel.get('isModified.fieldTwo'));// should show: "fieldTwo status: false false"
console.log('record status: ', myModel.get('isNew'), myModel.get('isModified'));// should show: "record status: false true"
console.log('Stringified record', Y.JSON.stringify(myModel));// should show: "Stringified record {"keys":{"primaryKey1":12,"primaryKey2":34},"values":{"fieldOne":{"prevVal":1,"newVal":3}}}"/*
Having the previous value for the changed field allows for building SQL statements such as:
UPDATE myTable set fieldOne = 3 where primaryKey1 = 12 and primaryKey2 = 34 and fieldOne = 1
The last conditional ensures that the modification is applied
only if the field to be changed has not been modified by other user
*/// The following will fail:
myModel.setValue('primaryKey1','whatever');// primary keys cannot be modified// The change event listener can serve to reject or modify a value being set
myModel.on('change',function(ev){switch(ev.name){// fieldOne will have its values doubledcase'fieldOne':
ev.newVal*=2;break;// fieldTwo will reject even valuescase'fieldTwo':if(ev.newVal=== Math.floor(ev.newVal/2)*2){
ev.halt();}break;}});
myModel.setValue('fieldOne',7);
console.log('fieldOne=7 doubled: ', myModel.getValue('fieldOne'));// should show: "fieldOne=7 doubled: 14"
myModel.setValue('fieldTwo',7);
console.log('fieldTwo=7 accepted: ', myModel.getValue('fieldTwo'));// should show: "fieldTwo=7 accepted: 7"
myModel.setValue('fieldTwo',6);
console.log('fieldTwo=6 rejected: ', myModel.getValue('fieldTwo'));// should show: "fieldTwo=6 rejected: 7"// There is also a multiple record extension with optiona sortingvar MultiRecordModel = Y.Base.create('multi-record', Y.GalleryModel,[Y.GalleryModelMultiRecord, Y.GalleryModelSortedMultiRecord]),
multiModel =new MultiRecordModel({primaryKeys:'primaryKeyField'}),
i;for(i =0; i <20; i +=1){
multiModel.add({primaryKeyField: Math.floor(Math.random()*9999), fieldOne:i});}
console.log('Values should show in ascending order');// Method each makes each record current and provides the index for it// By default the first primary key field is the sort field, in ascending order
multiModel.each(function(index){
console.log(index, multiModel.getValue('primaryKeyField'));});
console.log('Values should now show in descending order');
multiModel.set('sortDir','desc');
multiModel.each(function(index){
console.log(index, multiModel.getValue('primaryKeyField'));});// The sort field needs not be the primary key
multiModel.setAttrs({sortField:'fieldOne', sortDir:'asc'});// As you can guess, the records would now show sorted by field one// You can go to any record
multiModel.set('index',5);// if you modify a sorted field, it will relocate itself to its proper place
multiModel.setValue('fieldOne',1.5);// Now, it should no longer be at position 5 (the sixth counting from zero) but at position 2
console.log('The current record is now: ', multiModel.get('index'));// lets pretend we save the records at odd indexes
multiModel.each(function(index){if(index &1){
multiModel.save();}});// Though there are no provisions to save batches of records// if the load() method gets an array of records instead of a single record// it will load them each in its own shelf// You can also loop only through modified records (makes it easy to save them)// Only even ones should remain modified
multiModel.eachModified(function(index){
console.log('Modified record at:', index);});// You can search a record by the value, on sorted columns // The find method returns the index at which a particular value is found
console.log('Record with value 2 is now at position: ', multiModel.find(2,false));// By adding the second, false, argument, the model will not be positioned at that record.// The default is to get positioned.
console.log('The model contains: ', multiModel.size());
multiModel.empty();
console.log('The model contains none: ', multiModel.size());});});

All code on this site is licensed under the BSD License unless stated otherwise.