ExtJS 4 - 包含没有Id关系的其他模型的模型

时间:2014-02-25 10:37:59

标签: extjs

给定的是这样的嵌套模型结构:

Model Website
 + id
 + name
 + images[] // List of Image instances

Model Image
 + imageName
 + imageUrl

响应的序列化版本如下:

{
 "id": 4711,
 "name": "Some name",
 "images" [
  {"imageName": "Beach", "imageUrl": "http://example.com/whatever.jpg"},
  ...
 ]
}

此嵌套模型集保留在文档存储中,并在Website.id请求时返回。

嵌套的图像列表没有by-id-relation,因为它们直接作为列表保存在父模型中。据我所知,Ext.data.Model中的经典关系通过by-id-relation引用相关模型。

问题是:有什么方法可以告诉父模型在其图像列表中为每个孩子使用Image模型?

1 个答案:

答案 0 :(得分:2)

作为第一步,您可以使用字段类型auto将图像数据加载到模型中:

Ext.define('My.Model', {
    extend: 'Ext.data.Model'

    ,fields: [
        {name: 'images', type: 'auto'}
        // ... other fields
    }
});

然后:

myModel.get('images');

应该返回:

[
    {"imageName": "Beach", "imageUrl": "http://example.com/whatever.jpg"},
    ...
]

从那里,理论上你应该能够实现一个完全自动化的解决方案,从这个数据创建模型,并且 - 最难的部分 - 尝试保持这些创建的记录和父模型中的子数据同步。但这是一个非常复杂的黑客攻击,必须涵盖Ext代码库中的许多入口点。作为一个例子,我曾经试图为“有一个”关系做到这一点,代表a lot of code。结果,我从未花时间整合这段代码,最后从未使用它。

我更愿意提倡一个简单的本地(对模型)解决方案。您可以向模型添加一个简单的方法,以将图像作为记录。例如:

Ext.define('My.Model', {

    // ...

    ,getImages: function() {
        var store = this.imageStore;
        if (!store) {
            store = new Ext.data.Store({
                model: 'My.ImageModel'
                ,data: this.get('images') || []
            });
            this.imageStore = store;
        }
        return store;
    } 
});

为相关模型创建商店将使您不必使用代理和阅读器。它还为您提供了一个接口,该接口接近Ext的默认接口。

如果您需要支持为同一个父记录多次加载图像,则可以使用该字段的convert方法进行挂钩。

最后,您可能还需要处理关联数据的客户端修改,以便能够将它们保存到服务器。如果您的关联模型允许,您可以简单地使用子存储的sync方法(并且不要忘记在同步回调中​​更新父模型的数据!)。但是,如果关联的模型未连接到服务器端的端点,则应该能够挂钩serialize方法以将数据保存在关联的存储中(而不是存储在父存储中的数据)记录,如果您使用相关商店,将无法更新。

以下是显示两者的最后一个示例:

Ext.define('My.Model', {
    extend: 'Ext.data.Model'

    ,fields: [
        {
            name: 'images'
            ,type: 'auto'

            // enables associated data update
            ,convert: function(data) {
                var store = this.imageStore;
                if (store) {
                    store.loadData(data || []);
                }
                return data;
            }

            // enables saving data from the associated store
            ,serialize: function(value, record) {
                var store = record.imageStore,
                if (store) {
                    // care, the proxy we want is the associated model's one
                    var writer = store.proxy && store.proxy.writer;
                    if (writer) {
                        return Ext.Array.map(store.getRange(), function(record) {
                            return writer.getRecordData(record);
                        });
                    } else {
                        // gross implementation, simply use the records data object
                        return Ext.pluck(store.getRange(), 'data');
                    }
                } else {
                    return record.get('images');
                }
            }
        }

        // ... other fields
    }

    ,getImages: function() {
        var store = this.imageStore;
        if (!store) {
            store = new Ext.data.Store({
                model: 'My.ImageModel'
                ,data: this.get('images') || []
            });
            this.imageStore = store;
        }
        return store;
    } 
});

请注意我没有测试过这段代码,所以它可能仍然包含一些错误...但我希望它足以给你一般的想法!