1
votes

(ExtJS 4.0.7)

I'm using Model.save() to PUT an update to a server. Everything works fine and the server returns a simple JSON response {success: true} (HTTP status 200). Model.save() throws the following error, however:

Uncaught TypeError: Cannot read property 'data' of undefined

Here's where this is happening in the ExtJS code (src/data/Model.js):

save: function(options) {
   ...
   callback = function(operation) {
      if (operation.wasSuccessful()) {
         record = operation.getRecords()[0]; <-- getRecords() return an empty array
         me.set(record.data); <-- record is undefined, so .data causes error
   ...
}

I've figured out this is happening because Model.save() expects the server to respond with JSON for the entire object that was just updated (or created).

Does anyone know of a clever way to make Model.save() work when the server responds with a simple success message?

2
Actually, Model.save() expects the id of the newly created Model, you solution may be suitable for your needs but it doesn't give you the new id, it would be much better to get something like: {succes:true, result:{id:32}} so you have your new id for your Model, that way, if you want to make changes to your instance and submit it, you can.VoidMain

2 Answers

1
votes

I was able to come up with a work-around by using a custom proxy for the model, and overriding the update function:

Ext.define('kpc.util.CustomRestProxy', {
    extend: 'Ext.data.proxy.Rest',
    alias: 'proxy.kpc.util.CustomRestProxy',
    type: 'rest',

    reader : {
        root: 'data',
        type: 'json',
        messageProperty: 'message'
    },

    // Model.save() will call this function, passing in its own callback
    update: function(operation, callback, scope) {

        // Wrap the callback from Model.save() with our own logic
        var mycallback = function(oper) {
            // Delete the resultSet from the operation before letting
            // Model.save's callback use it; this will 
            oper.resultSet = undefined;
            callback(op);
        };

        return this.doRequest(operation, mycallback, scope);
    }
});

In a nutshell, when my proxy is asked to do an update it makes sure operation.resultSet == undefined. This changes the return value for operation.getRecords() (which you can see in the code sample from my question). Here's what that function looks like (src/data/Operation.js):

getRecords: function() {
    var resultSet = this.getResultSet();
    return (resultSet === undefined ? this.records : resultSet.records);
}

By ensuring that resultSet == undefined, operation.getRecords returns the model's current data instead of the empty result set (since the server isn't returning a result, only a simple success message). So when the callback defined in save() runs, the model sets its data to its current data.

0
votes

I investigate this problem and found truly simple answer. Your result must be like this:

{
  success: true,
  items: { id: '', otherOpt: '' }
}

And items property MUST be equal Model->Reader->root property (children in tree for example).

If you want to use items instead children you can use defaultRootProperty property in Store and configure your nested collections as you want.

PS

Object in items property must be fully defined because it replaces actual record in store.