Hybrid View
-
4 Mar 2013 1:30 PM #1
Are there ever going to be useful events on Ext.data.Model ?
Are there ever going to be useful events on Ext.data.Model ?
Currently in the 4.2 beta and the lower the Ext.data.Model methods of afterEdit, afterReject, afterCommit just call methods on the actual store object(s) if there is one linked. If you have a model without a store you are SOL, the only event that gets fired from Model is of all things 'idchanged'. Are there any plans to put these events into models?
-
6 Mar 2013 7:56 AM #2Sencha - Senior Forum Manager
- Join Date
- Mar 2007
- Location
- St. Louis, MO
- Posts
- 34,118
- Vote Rating
- 453
You could easily add events, for example a datachanged when you hit set (disclaimer: needs to be furthered to handle an object)
Code:Ext.define('Override.data.Model', { override : 'Ext.data.Model', set : function(fieldName, newValue) { var oldValue = this.get(fieldName), ret = this.callParent([fieldName, newValue]); this.fireEvent('datachanged', this, fieldName, newValue, oldValue); return ret; } }); Ext.define('MyModel', { extend : 'Ext.data.Model', fields : ['foo'] }); Ext.application({ name : 'Test', launch : function() { var model = new MyModel({ foo : 'bar' }); model.on('datachanged', function(record, fieldName, newValue, oldValue) { console.log('data changed', fieldName, newValue, oldValue); }); model.set('foo', 'mitch'); } });Mitchell Simoens @SenchaMitch
Sencha Inc, Senior Forum Manager
________________
http://www.JSONPLint.com - Source to lint your JSONP!
Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
https://github.com/mitchellsimoens
Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/
Need more help with your app? Hire Sencha Services services@sencha.com
Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is almost in print!
When posting code, please use BBCode's CODE tags.
-
6 Mar 2013 11:15 AM #3
But this logic already exists in store why would we want to duplicate it?
Would fire datachanged twice. The stores update event logic already handles this.Code:model.set('foo', 'mitch'); model.set('foo', 'mitch');
***
Yes I know we can have overrides that can do anything to the code but I think that this should be handled at the framework level. If you guys have no intention adding the events we can add them ourselves which is fine with us. I'd be worried about if we publish these events in our code developers rely on these events but then in 4.2 you guys publish something very similar. That would start us down the path of a complicated deprecation and refactoring process.
-
6 Mar 2013 11:51 AM #4
Here is my proposed solution to the problem if there there will be no work done to improve the model event system. There probably is some bugs in it but I whipped it in less than 30 mins. It is a complete hack of a bad design imo.
I have designed a record based form with has it's saving, reading and writing and other logic go through the model instead of the Form submit actions. My problem is that there are no useful update events on the model itself without a store.Code:Ext.override(Ext.data.Model, { relayStoreEvents: function(events) { if (!this._eventsStore) { this._eventsStore = new Ext.data.Store({ model: this.self }); this.join(this._eventsStore); this.relayEvents(this._eventsStore, events || ['update']); } } });
But I can do something like :
In another part of the code I can publish the update events on the rec through the RecordForm.Code:Ext.define('RecordForm', loadRecord: function(rec) { var ret = this.callParent(arguments); rec.relayStoreEvents(); return ret; } }
-
6 Mar 2013 2:12 PM #5
-
Today 4:17 AM #6
I spent some hours on the topic of missing CRUD Events on models, this is what i got so far:
(changes in Bold)
For me this solution works for what i need it, in special syncing hasMany Associations after create in a custom Model Class:Code:Ext.override(Ext.data.Model,{ inheritableStatics: { load: function(id, config) { config = Ext.apply({}, config); config = Ext.applyIf(config, { action: 'read', id : id }); var operation = new Ext.data.Operation(config), scope = config.scope || this, callback, me = this.prototype; callback = function(operation) { var record = null, success = operation.wasSuccessful(); if (success) { record = operation.getRecords()[0]; record.fireEvent('read',record,operation); // If the server didn't set the id, do it here if (!record.hasId()) { record.setId(id); } Ext.callback(config.success, scope, [record, operation]); } else { Ext.callback(config.failure, scope, [record, operation]); } Ext.callback(config.callback, scope, [record, operation, success]); }; this.getProxy().read(operation, callback, this); } }, save: function(options) { options = Ext.apply({}, options); var me = this, action = me.phantom ? 'create' : 'update', scope = options.scope || me, stores = me.stores, i = 0, storeCount, store, operation, callback; Ext.apply(options, { records: [me], action : action }); operation = new Ext.data.Operation(options); callback = function(operation) { var success = operation.wasSuccessful(); me.fireEvent(operation.action,me,operation); if (success) { for(storeCount = stores.length; i < storeCount; i++) { store = stores[i]; store.fireEvent('write', store, operation); store.fireEvent('datachanged', store); // Not firing refresh here, since it's a single record } Ext.callback(options.success, scope, [me, operation]); } else { Ext.callback(options.failure, scope, [me, operation]); } Ext.callback(options.callback, scope, [me, operation, success]); }; me.getProxy()[action](operation, callback, me); return me; }, destroy: function(options) { options = Ext.apply({ records: [this], action : 'destroy' }, options); var me = this, isNotPhantom = me.phantom !== true, scope = options.scope || me, stores, i = 0, storeCount, store, args, operation, callback; operation = new Ext.data.Operation(options); callback = function(operation) { me.fireEvent(operation.action,me,operation); args = [me, operation]; // The stores property will be mutated, so clone it first stores = Ext.Array.clone(me.stores); if (operation.wasSuccessful()) { for (storeCount = stores.length; i < storeCount; i++) { store = stores[i]; // If the store has a remove (it's not a TreeStore), then // remove this record from Store. Avoid Store handling anything by passing the "isMove" flag if (store.remove) { store.remove(me, true); } // Other parties may need to know that the record as gone // eg View SelectionModels store.fireEvent('bulkremove', store, [me], [store.indexOf(me)], false); if (isNotPhantom) { store.fireEvent('write', store, operation); } } me.clearListeners(); Ext.callback(options.success, scope, args); } else { Ext.callback(options.failure, scope, args); } Ext.callback(options.callback, scope, args); }; // Not a phantom, then we must perform this operation on the remote datasource. // Record will be removed from the store in the callback upon a success response if (isNotPhantom) { me.getProxy().destroy(operation, callback, me); } // If it's a phantom, then call the callback directly with a dummy successful ResultSet else { operation.complete = operation.success = true; operation.resultSet = me.getProxy().reader.nullResultSet; callback(operation); } return me; } });
There might be more elegant ways to get these events, in special the load within the statics is a bit painful and might not be reliable.Code:'create': function(model,operation) { var result = operation.response.result; Ext.iterate(model.associations.items,function(association){ if(association.type == 'hasMany') { if(result[association.name]) { resultData = result[association.name]; modelStore = model[association.storeName]; delete modelStore.snapshot; modelStore.clearData(true); extractedResults = modelStore.proxy.reader.extractData(resultData); modelStore.data.addAll(extractedResults); } } }); },
Anyway, it would be great if sencha could offer CRUD Events on models by default.
Best regards,
Alex


Reply With Quote