Ext.data.Model-EXTJS-15037.js (7279B)
1 /** 2 * This is a bugfix when a save operation on a model does not update associations returned by the server. 3 * 4 * The forum thread can be found at https://www.sencha.com/forum/showthread.php?302635-Ext.data.operation.Operation.doProcess-doesn-t-update-associations&p=1106828 5 */ 6 Ext.define("PartKeepr.data.Model", { 7 override: 'Ext.data.Model', 8 9 hasField: function (fieldName) { 10 var fields = this.getFields(); 11 12 13 for (var i in fields) { 14 if (fields[i].name == fieldName && fields[i].reference === null) { 15 return true; 16 } 17 } 18 19 return false; 20 }, 21 /** 22 * Saves the model instance using the configured proxy. 23 * @param {Object} [options] Options to pass to the proxy. Config object for {@link Ext.data.operation.Operation}. 24 * @return {Ext.data.operation.Operation} The operation 25 */ 26 save: function (options) { 27 options = Ext.apply({}, options); 28 29 var me = this, 30 phantom = me.phantom, 31 dropped = me.dropped, 32 action = dropped ? 'destroy' : (phantom ? 'create' : 'update'), 33 scope = options.scope || me, 34 callback = options.callback, 35 proxy = me.getProxy(), 36 operation; 37 38 options.records = [me]; 39 40 options.recordCreator = function (data, type, readOptions) { 41 // Important to change this here, because we might be loading associations, 42 // so we do not want this to propagate down. If we have a session, use that 43 // so that we end up getting the same record. Otherwise, just remove it. 44 var session = me.session; 45 if (readOptions) { 46 readOptions.recordCreator = session ? session.recordCreator : null; 47 } 48 me.set(data, me._commitOptions); 49 //<debug> 50 // Do the id check after set since converters may have run 51 /*if (doIdCheck && me.getId() !== id) { 52 Ext.Error.raise('Invalid record id returned for ' + id + '@' + me.entityName); 53 }*/ 54 //</debug> 55 return me; 56 }; 57 58 options.internalCallback = function (operation) { 59 var args = [me, operation], 60 success = operation.wasSuccessful(); 61 if (success) { 62 Ext.callback(options.success, scope, args); 63 } else { 64 Ext.callback(options.failure, scope, args); 65 } 66 args.push(success); 67 Ext.callback(callback, scope, args); 68 }; 69 delete options.callback; 70 71 operation = proxy.createOperation(action, options); 72 73 // Not a phantom, then we must perform this operation on the remote datasource. 74 // Record will be removed from the store in the callback upon a success response 75 if (dropped && phantom) { 76 // If it's a phantom, then call the callback directly with a dummy successful ResultSet 77 operation.setResultSet(Ext.data.reader.Reader.prototype.nullResultSet); 78 me.setErased(); 79 operation.setSuccessful(true); 80 } else { 81 operation.execute(); 82 } 83 return operation; 84 } 85 }); 86 87 Ext.define('PartKeepr.data.operation.Update', { 88 override: 'Ext.data.operation.Update', 89 90 action: 'update', 91 92 isUpdateOperation: true, 93 94 order: 20, 95 doProcess: Ext.emptyFn, 96 doExecute: function () { 97 return this.getProxy().update(this); 98 } 99 }); 100 101 Ext.define('PartKeepr.data.operation.Create', { 102 override: 'Ext.data.operation.Create', 103 104 action: 'create', 105 106 isCreateOperation: true, 107 108 order: 10, 109 doProcess: Ext.emptyFn, 110 doExecute: function() { 111 return this.getProxy().create(this); 112 } 113 }); 114 115 Ext.define("PartKeepr.data.schema.Role", { 116 override: "Ext.data.schema.Role", 117 118 getAssociatedStore: function (inverseRecord, options, scope, records, isComplete) { 119 // Consider the Comment entity with a ticketId to a Ticket entity. The Comment 120 // is on the left (the FK holder's side) so we are implementing the guts of 121 // the comments() method to load the Store of Comment entities. This trek 122 // begins from a Ticket (inverseRecord). 123 124 var me = this, 125 storeName = me.getStoreName(), 126 store = inverseRecord[storeName], 127 load = options && options.reload, 128 source = inverseRecord.$source, 129 session = inverseRecord.session, 130 args, i, len, raw, rec, sourceStore; 131 132 if (!store) { 133 // We want to check whether we can automatically get the store contents from the parent session. 134 // For this to occur, we need to have a parent in the session, and the store needs to be created 135 // and loaded with the initial dataset. 136 if (!records && source) { 137 source = source[storeName]; 138 if (source && !source.isLoading()) { 139 sourceStore = source; 140 records = []; 141 raw = source.getData().items; 142 143 for (i = 0, len = raw.length; i < len; ++i) { 144 rec = raw[i]; 145 records.push(session.getRecord(rec.self, rec.id)); 146 } 147 isComplete = true; 148 } 149 } 150 store = me.createAssociationStore(session, inverseRecord, records, isComplete); 151 store.$source = sourceStore; 152 153 if (!records && (me.autoLoad || options)) { 154 load = true; 155 } 156 157 inverseRecord[storeName] = store; 158 } else { 159 if (records) { 160 store.loadData(records); 161 } 162 } 163 164 if (options) { 165 // We need to trigger a load or the store is already loading. Defer 166 // callbacks until that happens 167 if (load || store.isLoading()) { 168 store.on('load', function (store, records, success, operation) { 169 args = [store, operation]; 170 scope = scope || options.scope || inverseRecord; 171 172 if (success) { 173 Ext.callback(options.success, scope, args); 174 } else { 175 Ext.callback(options.failure, scope, args); 176 } 177 args.push(success); 178 Ext.callback(options, scope, args); 179 Ext.callback(options.callback, scope, args); 180 }, null, {single: true}); 181 } else { 182 // Trigger straight away 183 args = [store, null]; 184 scope = scope || options.scope || inverseRecord; 185 186 Ext.callback(options.success, scope, args); 187 args.push(true); 188 Ext.callback(options, scope, args); 189 Ext.callback(options.callback, scope, args); 190 } 191 } 192 193 if (load && !store.isLoading()) { 194 store.load(); 195 } 196 197 return store; 198 }, 199 }); 200 201 Ext.define("PartKeepr.data.proxy.Proxy", { 202 override: "Ext.data.proxy.Proxy", 203 204 batch: function (options, /* deprecated */listeners) { 205 return this.callParent(arguments); 206 } 207 });