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

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

问题描述

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



示例模型&商店定义:

  Ext.define(App.model.test.Parent,{
扩展:'Ext.data.Model',
需要:['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'
},

作者:{
类型:'json',
writeAllFields:true
}
}
});

Ext.define(App.model.test.Child,{
extends:'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',
extends:'Ext.data.Store',
模型:'App.model.test.Parent',
autoLoad:true,
autoSync:false
});

应用程序服务器响应代理的 READ 请求与单个模型及其相关联的数据。这是所有工作的hunky dory!



服务器响应阅读请求

  {
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(辛普森孩子,孩子们); // [> constructor,> constructor,> constructor]

不符合行为开始保存和更新请求



以下是对 UPDATE 请求...

$ b的测试响应
$ b

  / **服务器更新响应* / 
{
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
}


/ **将调用代理UPDATE,响应在* /
homer.save({
success:function(rec,op){
var savedRec = op.getRecords()。pop(),
kidNames ='';
安慰。日志(savedRec.get(名)); // SAVED Homer Simpson = CORRECT!
Ext.each(savedRec.getKids()。getRange(),function(kid){
kidNames + = kid.get('name')+,;
});
console.log(kids);
//输出:Bart Simpson,Lisa Simpson,Maggie Simpson = WRONG !!
}
})

我注意到,如果我检查服务器,生成的关联商店(即, getKidsStore )包含的记录是原始记录,即他们的名字中没有SAVED。然而,返回的记录的孩子属性确实包含正确的数据。



如果我明白问题正确的是, Ext.data.reader.Reader 没有正确地更新关联的存储与 .save()中包含的关联数据, 回应。如果是这样,在我看来,这是非常不直观的,因为我希望与处理 store.load()请求的读者相同的行为,并将生成的关联商店填充到



任何人都可以指出正确的方向来实现我以后的行为?



免责声明:同样的问题在此提出: ExtJs 4 - 在记录保存中加载嵌套数据,但无响应。我觉得我的问题要更详细一些..



编辑:我已经在Sencha论坛上发布了这个问题: http://www.sencha.com编辑(8/23 /

>我发现了这个问题,或者说, getRecords()中的 Ext.data方法。操作。该方法返回操作初始配置的记录将被返回,尽管代理可以在操作初始化后的某个时候修改这些记录的数据。根据文档。



这是相当混乱的IMO,因为返回的记录确实已更新,但生成的关联存储,因此关联的数据,不是!这是导致我的混乱,似乎记录包含来自应用程序服务器的更新数据,但情况并非如此。



为了帮助我从响应中获取 FULLY 更新数据的简单思想,我已经添加了一个方法到 Ext.data.Operation class ...我只是写了这个方法,没有测试它,而不是确保我正在寻找的功能,所以使用自己的风险!



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

  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.O peration] EXCEPTION:resultSet不包含记录!;
}

}
});

现在我可以实现我以后的功能了...

  //获取未保存的数据
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

//在代理上调用UPDATE方法
//查看服务器响应的原始帖子
home.save({
success:function(rec,op){
var savedRecord = op.getSavedRecord(),// magic!/ sarcasm
savedKids ='';

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

console.log(Saved Children,savedKids);

/ **输出现在正确!!
SAVED Bart Simpson,SAVED Lisa Simpson,SAVED Maggie Simpson
* /
}
});

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

  / ** 
*提供更新到提供的模型的方法,包括任何关联的数据
* @param {Ext.data。 Model} model要更新的模型实例。必须具有与当前模型相同的modelName
* @return {Ext.data.Model}更新的模型
* /
updateTo:function(model){
var me =这个,
that = model,
associations = me.associations.getRange();

if(me.modelName!== that.modelName)
throw TypeError(updateTo需要与当前实例(+ me.modelName +)相同类型的模型。 + that.modelName +提供。);

//首先只是更新模型字段和值
me.set(that.getData());

//现在更新关联
Ext.each(associations,function(assoc){
switch(assoc.type){
/ **
* hasOne关联存在于当前模型(我)上作为关联模型的一个实例
*这个实例,因此关联可以通过检索实例和
*来调用set
* /
casehasOne:
var instanceName = assoc.instanceName,
currentInstance = me [instanceName],
updatedInstance = that [instanceName];

//使用提供的模型中的数据更新当前模型的hasOne实例
currentInstance.set(updatedInstance.getData());

break;

/ **
* hasMany关联从商店运行,所以我们需要检索更新的关联
*从提供的模型的数据(它),并将其提供给当前模型(我)assocStore
* /
casehasMany:
var assocStore = me [assoc.storeName ],
getter = assoc.name,
newData = that [getter]()。getRange();

//使用提供的模型的hasMany存储
assocStore.loadData(newData)更新当前模型的hasMany关联存储库中的数据;
break;

//如果由于某种原因造成虚假的关联类型通过,抛出一个类型错误
//此时我的应用程序中没有belongsTo关联,所以这个TypeError
//如果我决定实施,可能有一天会出现。
default:
throw TypeError(updateTo不知道如何处理关联类型:+ assoc.type);
break;
}
});

//提交这些更改
me.commit();

返回我;
}

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

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

//保存请求
order.save({
scope:me,
success:function(responseRecord,operation){
// note:responseRecord没有更新的关联,根据post
var serverRecord = operation.getSavedRecord(),
storeRecord = orderStore.getById(order.getId());

switch(operation.action){
case'create':
//将新记录添加到客户端存储
orderStore.add(serverRecord);
break;

case'update':
//更新现有记录,包括在服务器响应中的AND关联
storeRecord.updateTo(serverRecord);
break;
}
}
});
}

我希望这可以帮助那些像我一样困惑的人!


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...

Example Model & Store Definition:

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
});

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

Server Response to READ Request

{
"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
}

Thus far, everything is working according to plan...

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

THE UNDESIRED BEHAVIOR BEGINS WITH SAVE AND UPDATE REQUESTS

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!!
    }
})

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.

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?

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..

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

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

解决方案

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.

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.

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!

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
          */
    }
});

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天全站免登陆