ExtJS 4.1 - 在 Model.Save() 响应中返回相关数据 [英] ExtJS 4.1 - Returning Associated Data in Model.Save() Response

查看:26
本文介绍了ExtJS 4.1 - 在 Model.Save() 响应中返回相关数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇为什么 Model.save() 响应的结果集中包含的记录没有正确返回更新的关联数据,尽管更新的数据包含在服务器响应中...

I am curious as to why the record contained in the result set of a Model.save() response does not properly return updated associated data, despite the updated data being contained in the server response...

示例模型和商店定义:

Ext.define("App.model.test.Parent",{
    extend: 'Ext.data.Model',
    requires: ['App.model.test.Child'],
    fields: [
            {name: 'id', type: 'int' },
            {name: 'name', type: 'string'},
            {name: 'kids', type: 'auto', defaultValue: []}
    ],
    idProperty: 'id',

    hasMany: [{
            foreignKey: 'parent_id',
            model: 'App.model.test.Child', 
            associationKey: 'kids',
            name: 'getKids'   
    }],

    proxy: {
        type: 'ajax',
        api : {
            create: '/service/test/create/format/json',
            read : '/service/test/read/format/json',
            update : '/service/test/update/format/json'
        },

        reader: {
            idProperty      : 'id',
            type            : 'json',
            root            : 'data',        
            successProperty : 'success',       
            messageProperty : 'message'
        },

        writer: {
            type            : 'json',
            writeAllFields  : true
        }
    }
});

Ext.define("App.model.test.Child",{
    extend: 'Ext.data.Model',
    fields: [
        {name: 'id', type: 'int' },
        {name: 'name', type: 'string'},
        {name: 'parent_id', type: 'int'}
    ]
});

Ext.define("App.store.test.Simpson",{
    storeId: 'TheSimpsons',
    extend: 'Ext.data.Store',
    model : 'App.model.test.Parent',
    autoLoad: true,
    autoSync: false
});

应用服务器对代理的 READ 请求的响应,使用单个模型及其关联数据.这都是工作的笨蛋多莉!

The application server response to the proxy's READ request with a single model, and its associated data. This is all working hunky dory!

服务器对 READ 请求的响应

{
"data":{
    "id":1,
    "name":"Homer Simpson",
    "children":{
        "1":{
            "id":1,
            "name":"Bart Simpson"
        },
        "2":{
            "id":2,
            "name":"Lisa Simpson"
        },
        "3":{
            "id":3,
            "name":"Maggie Simpson"
        }
    }
},
"success":true,
"message":null
}

到目前为止,一切都在按计划进行......

store = Ext.create("App.store.test.Simpson");
homer = store.getById(1);
kids  = homer.getKids().getRange();
console.log("The Simpson Kids", kids);  // [>constructor, >constructor, >constructor]

不良行为始于保存和更新请求

这是我对 UPDATE 请求的测试响应...

Here is my test response for the UPDATE Request...

/** Server UPDATE Response */
{
"data":{
    "id":1,
    "name":"SAVED Homer Simpson",
    "kids":[{
        "id":1,
        "name":"SAVED Bart Simpson",
        "parent_id":1
    },{
        "id":2,
        "name":"SAVED Lisa Simpson",
        "parent_id":1
    },{
        "id":3,
        "name":"SAVED Maggie Simpson",
        "parent_id":1
    }]
},
"success":true,
"message":null
}


/** Will call proxy UPDATE, response is above */
homer.save({
    success: function(rec, op){
        var savedRec = op.getRecords().pop(),
            kidNames = '';
        console.log(savedRec.get('name')); // SAVED Homer Simpson = CORRECT!
        Ext.each(savedRec.getKids().getRange(), function(kid){
            kidNames += kid.get('name') + ", ";
        });
        console.log(kids); 
        //Outputs: Bart Simpson, Lisa Simpson, Maggie Simpson = WRONG!!
    }
})

我注意到,如果我检查服务器返回的记录,生成的关联存储(即,getKidsStore)包含的记录是原始记录,即它们没有SAVED"他们的名字.然而,返回记录的 kids 属性确实包含正确的数据.

I notice that if I inspect the record returned by the server, the generated Association Store (i.e., getKidsStore) the contained records are the original records, i.e., they do not have "SAVED" in their name. The kids property of the returned record, however, DOES indeed contain the correct data.

如果我正确理解了这个问题,那就是 Ext.data.reader.Reader 没有使用 .save()<中包含的关联数据正确更新关联存储/code> 响应.如果是这样,在我看来,这是非常不直观的,因为我期望与处理 store.load() 请求并开始填充生成的关联存储的读取器具有相同的行为.

If I understand the issue correctly, it is that the Ext.data.reader.Reader does not correctly update the associated store with the associated data contained in the .save() response. If so, in my opinion, this is very unintuitive as I would expect the same behavior as the reader that handles the store.load() request and populates the generated association stores to begin with.

谁能为我指明正确的方向来实现我所追求的行为?

Can anyone point me in the right direction in achieving the behavior I'm after?

免责声明:这里问了同样的问题:ExtJs 4 - 在记录保存时加载嵌套数据 但没有响应.我觉得我的问题要更彻底一些..

Disclaimer: Same question was asked here: ExtJs 4 - Load nested data on record save but with no response. I feel my question to be a bit more thorough..

我已经在 Sencha 论坛上发布了这个问题:http://www.sencha.com/forum/showthread.php?270336-Associated-Data-in-Model.save()-Response

I have posted this question over on the Sencha forums: http://www.sencha.com/forum/showthread.php?270336-Associated-Data-in-Model.save()-Response

编辑(2013 年 8 月 23 日):我用一个完整的示例以及其他发现重新编写了这篇文章...

EDIT (8/23/13): I re-wrote this post with a COMPLETE example, as well as additional findings...

推荐答案

我发现了问题,或者更确切地说,困惑在于 getRecords() 方法Ext.data.Operation.此方法返回将返回操作的初始配置记录,尽管代理可能会在操作初始化后的某个时间修改这些记录的数据." 根据文档.

I've found the issue, or rather, confusion lies in the getRecords() method of the Ext.data.Operation. This method returns "the operation's initially configured records will be returned, although the proxy may modify these records' data at some point after the operation is initialized." as per the documentation.

这是相当令人困惑的 IMO,因为返回的记录确实更新了,但是生成的关联存储,因此关联的数据,不是!这就是导致我困惑的原因,看起来好像记录包含来自应用服务器的更新数据,但事实并非如此.

This is rather confusing IMO, as the returned record is indeed updated, however the generated association store, and therefore associated data, is not! This is what lead to my confusion, it appeared as though the record contained the updated data from the application server, but this was not the case.

为了帮助我的头脑简单地从响应中获取完全更新的数据,我在 Ext.data.Operation 类中添加了一个方法...我只是写了这个方法,除了确保我正在寻找的功能之外还没有对其进行测试,所以使用风险自负!

In order to aid my simple mind in obtaining the FULLY updated data from the response, I have added a method to the Ext.data.Operation class... I just wrote this method and haven't tested it more than ensuring the functionality I was looking for, so use at your own risk!

请记住,我不调用 store.sync(),而是实例化一个模型并调用 model.save() 方法,因此我的 resultSet 通常只包含一条记录...

Please keep in mind that I do not call store.sync(), rather I instantiate a model and call the model.save() method, so my resultSet typically only ever contains a single record...

Ext.override(Ext.data.Operation,{
    getSavedRecord: function(){
        var me = this, // operation
            resultSet = me.getResultSet();

        if(resultSet.records){
            return resultSet.records[0];
        }else{
            throw "[Ext.data.Operation] EXCEPTION: resultSet contains no records!";
        }

    }
});

现在我可以实现我想要的功能了...

Now I am able to achieve the functionality I was after...

// Get the unsaved data
store = Ext.create('App.store.test.Simpson');
homer = store.getById(1);
unsavedChildren = '';

Ext.each(homer.getKids().getRange(), function(kid){
    unsavedChildren += kid.get('name') + ",";
});

console.log(unsavedChildren); // Bart Simpson, Lisa Simpson, Maggie Simpson

// Invokes the UPDATE Method on the proxy
// See original post for server response
home.save({
    success: function(rec, op){
        var savedRecord = op.getSavedRecord(), // the magic! /sarcasm
            savedKids   = '';

        Ext.each(savedRecord.getKids().getRange(), function(kid){
            savedKids += kid.get('name') + ',';
        });

        console.log("Saved Children", savedKids);

        /** Output is now Correct!!
            SAVED Bart Simpson, SAVED Lisa Simpson, SAVED Maggie Simpson
          */
    }
});

编辑 12/10/13我还向 Ext.data.Model 添加了一个方法,我将其称为 updateTo,该方法处理将记录更新到提供的记录,它还处理关联.我将它与上面的 getSavedRecord 方法结合使用.请注意,这不会处理任何 belongsTo 关联,因为我没有在我的应用程序中使用它们,但该功能很容易添加.

Edit 12/10/13 I also added a method to Ext.data.Model which I called updateTo which handles updating a record to the provided record, which also handles associations. I use this in conjunction with the above getSavedRecord method. Please note this does not handle any belongsTo associations as I don't use them in my application, but that functionality would be easy to add.

/**
 * Provides a means to update to the provided model, including any associated data
 * @param {Ext.data.Model} model The model instance to update to. Must have the same modelName as the current model
 * @return {Ext.data.Model} The updated model
 */
updateTo: function(model){
    var me = this,
    that = model,
    associations = me.associations.getRange();

    if(me.modelName !== that.modelName)
    throw TypeError("updateTo requires a model of the same type as the current instance ("+ me.modelName +"). " + that.modelName + " provided.");

    // First just update the model fields and values
    me.set(that.getData());

    // Now update associations
    Ext.each(associations, function(assoc){
    switch(assoc.type){
        /**
         * hasOne associations exist on the current model (me) as an instance of the associated model.
         * This instance, and therefore the association, can be updated by retrieving the instance and
         * invoking the "set" method, feeding it the updated data from the provided model.
         */
        case "hasOne":
            var instanceName  = assoc.instanceName,
                currentInstance = me[instanceName],
                updatedInstance = that[instanceName];

             // Update the current model's hasOne instance with data from the provided model
             currentInstance.set(updatedInstance.getData());

            break;

        /** 
         * hasMany associations operate from a store, so we need to retrieve the updated association
         * data from the provided model (that) and feed it into the current model's (me) assocStore
         */
        case "hasMany":
            var assocStore = me[assoc.storeName],
                getter     = assoc.name,
                newData    = that[getter]().getRange();

            // Update the current model's hasMany association store with data from the provided model's hasMany store
            assocStore.loadData(newData);
            break;

        // If for some reason a bogus association type comes through, throw a type error
        // At this time I have no belongsTo associations in my application, so this TypeError
        // may one day appear if I decide to implement them.
        default:
            throw TypeError("updateTo does not know how to handle association type: " + assoc.type);
            break;
    }
    });

    // Commit these changes
    me.commit();

    return me;
}

所以基本上我做这样的事情(理论上这将在订单控制器中)

So basically I do something like this (this would theoretically be in the Order controller)

doSaveOrder: function(order){
    var me = this,                       // order controller 
        orderStore = me.getOrderStore(); // magic method

    // Save request
    order.save({
        scope: me,
        success: function(responseRecord, operation){ 
            // note: responseRecord does not have updated associations, as per post
            var serverRecord = operation.getSavedRecord(),
                storeRecord  = orderStore.getById(order.getId());

            switch(operation.action){
                case 'create':
                    // Add the new record to the client store
                    orderStore.add(serverRecord);
                break;

                case 'update':
                    // Update existing record, AND associations, included in server response
                    storeRecord.updateTo(serverRecord);
                break;
            }
        }
    });
}

我希望这能帮助像我一样困惑的人!

I hope this helps someone who was confused as I was!

这篇关于ExtJS 4.1 - 在 Model.Save() 响应中返回相关数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆