【问题标题】:How to create nested models in Ember.js?如何在 Ember.js 中创建嵌套模型?
【发布时间】:2012-02-29 11:14:59
【问题描述】:

通过 Ember.js 文档,我无法弄清楚如何创建嵌套模型。假设我有以下 JSON:

App.jsonObject = {
    id: 1812,
    name: 'Brokerage Account',
    positions: [
        {
            symbol: 'AAPL',
            quantity: '300'
        },
        {
            symbol: 'GOOG',
            quantity: '500'
        }
    ]
}

如果我创建这样的模型对象

App.account = Ember.Object.create(App.jsonObject);

只有顶层属性(id 和 name)被绑定到模板,嵌套的位置数组没有被正确绑定。因此,添加、删除或更新位置不会影响显示。是否有手动或自动的方法来转换位置数组以使其具有绑定意识(类似于 WPF 中的 ObservableCollection)?

我创建了一个 jsfiddle 来试验这个:http://jsfiddle.net/nareshbhatia/357sg/。如您所见,对顶级属性的更改会反映在输出中,但对位置的任何更改都不会。我将非常感谢有关如何执行此操作的任何提示。

谢谢。

纳雷什

编辑: 理想的情况是 Ember.js 能够以某种方式将我的 JSON 提要解析为嵌套的 Ember.js 对象。例如,如果我如下明确定义我的类,是否可以帮助 Ember.js 创建正确的对象?

App.Account = Ember.Object.extend({
    id: null,
    name: null,
    positions: Ember.ArrayProxy.create()
});

App.Position = Ember.Object.extend({
    symbol: null,
    quantity: null,
    lastTrade: null
});

App.account = App.Account.create(App.jsonObject);

我的最终目标是在分层网格中显示此结构,该网格可以在帐户级别展开/折叠。来自 WPF/Silverlight 世界,做这样的事情相当容易。您需要做的就是在 XAML 中为网格指定一个嵌套模板,它知道如何解释您的模型。你可以找到一个例子here - 这并不难理解。我想知道在 Ember.js 中是否有可能发生这样的事情。

【问题讨论】:

  • 我对 WPF 或它的控件不是很熟悉(近 4 年没有使用它),但看起来在 Ember & 中实现这样的东西应该还不错车把。

标签: ember.js


【解决方案1】:

与 Ember 2.5.0 / 2016 年 5 月相关的答案

我有一个类似的问题(我的案例见下文),并且对众多过时/不再有用的线程感到沮丧,所以我在这里发布我学到的东西,以防它对其他偶然发现这个问题的人有所帮助页面。

TL;DR:在最新版本的 Ember 中,您可以通过使用所需属性扩展 ember-data 中的 Model 对象来定义模型。属性通过调用DS.attr(type) 定义(其中type 参数可以省略以传递您想要的任何类型,例如来自您的JSON 的嵌套对象)。

所以对于这个问题,您可以创建app/models/account(可能使用 ember-cli --> ember g resource account):

import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { hasMany } from 'ember-data/relationships';

export default Model.extend({
    name: attr('string'),
    positions: hasMany('position')
});

app/models/position 也是如此:

import Model from 'ember-data/model';
import attr from 'ember-data/attr';

export default Model.extend({
    symbol: attr('string'),
    quantity: attr('number')
});

我的情况:

我想要一个deviceconnection 相关联,该connection 可能是串行或TCP 连接,每个都有不同的选项/参数。在普通的 JS 中,我会做这样的事情:

[{
    name: "My serial device",
    connection: {
        type: "serial",
        options: {
            port: "COM1",
            baud: 115200,
            data_bits: 8,
            parity: "none",
            stop_bits: 1,
            flow_control: "none"
        }
    }
}, {
    name: "My TCP/IP device",
    connection: {
        type: "tcp",
        options: {
            host: "127.0.0.1",
            port: 23
        }
    }
}]

在 Ember 中,这将转换为具有类型为对象(未指定)的连接属性的 device 模型:

import Model from 'ember-data/model';
import attr from 'ember-data/attr';

export default Model.extend({
    name: attr('string'),
    connection: attr()
});

如果您想知道什么是确定某个东西是否应该是它自己的模型(与belongsTohasMany 等关系)的好标准,首先要问一个简单的问题是否则,有问题的资源将具有与之关联的 ID 号。在这种情况下,单独跟踪连接和设备没有多大意义,因此我选择不为连接创建单独的模型。

【讨论】:

    【解决方案2】:

    我基于 Alexandros K 的解决方案编写了自己的简单模型工厂,但支持 ES6 模块。以为我会分享它:)

    import Ember from 'ember';
    
    var ModelFactory = Ember.Object.extend({});
    
    ModelFactory.reopenClass({
        getType(obj) {
            if(!obj) {
                return null;
            }
    
            if(Array === obj.constructor) {
                return "array";
            }
            else if(typeof obj === "object") {
                return "object";
            }
    
            return null;
        },
    
        // Factory method..
        create: function (arg) {
    
            const _this = this;
    
            switch (this.getType(arg)) {
    
                // Return an Ember Array
                case "array":
    
                    var newArray = [];
    
                    arg.forEach(function(item) {
                        newArray.pushObject(_this.create(item));
                    });
    
                    return newArray;
    
                // Or a recursive object.
                case "object":
    
                    var newObject = Ember.Object.create();
    
                    for (var key in arg) {
                        if (arg.hasOwnProperty(key)) {
                            newObject.set(key, this.create(arg[key]));
                        }
                    }
    
                    return newObject;
    
                default:
    
                    // Or just return the args.
                    return arg;
            }
        }
    });
    
    
    export default ModelFactory;
    

    用法:

    ModelFactory.create(json)
    

    【讨论】:

      【解决方案3】:

      我创建了一个你可能喜欢的递归对象工厂:

      它将遍历对象并创建 Ember 数组或嵌套对象,返回完整的 Ember 对象树!

      这是供您参考的来源,以及一个 JS 小提琴:http://jsfiddle.net/SEGwy/2/

      请注意:小提琴将输出写入控制台,因此您不会在屏幕上看到任何输出。

        RecursiveObject = {
      
            // http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
            TypeOf: function (input) {
                try {
                    return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
                } catch (e) {
                    return typeof input;
                }
            },
      
            // Factory method..
            create: function (args) {
      
                args = args || {};
                ctxt = this;
      
                switch (this.TypeOf(args)) {
      
                    // Return an Ember Array
                    case "array":
      
                        var result = Ember.A();
      
                        for (var i = 0; i < args.length; i++) {
                            x = this.create(args[i]);
                            result.push(x);
                        };
      
                        break;
      
                    // Or a recursive object.
                    case "object":
      
                        var result = Ember.Object.create();
      
                        $.each(args, function (key, value) {
      
                            result.set(key, ctxt.create(value));
      
                        });
      
                        break;
      
                    default:
      
                        // Or just return the args.
                        result = args;
                        break;
      
                }
      
                return result;
      
            }
      
        }
      
        // Example
      
        jsonObject = {
          id: 1812,
          name: 'Brokerage Account',
          positions: [
              {
                  symbol: 'AAPL',
                  quantity: '300'
              },
              {
                  symbol: 'GOOG',
                  quantity: '500'
              }
          ]
        }
      
        x = RecursiveObject.create(jsonObject);
        console.log(x);
      

      【讨论】:

        【解决方案4】:

        当使用绑定添加到 Ember 数组对象时,您需要使用 pushObject 而不是 push。在访问positions 属性时,您可能应该使用get()。请参阅我的 jsFiddle 进行更正。

        http://jsfiddle.net/ud3323/Y5nG5/

        【讨论】:

        • 谢谢。这非常有用,因为它允许我将职位视为一流的财产。但是,它仍然不能解决嵌套级别的属性问题(我的小提琴末尾附近的注释行)。我已经编辑了我的问题以澄清我更高级别的目标。我会对你对此的看法很感兴趣。再次感谢。
        • 对于嵌套数组,您必须遍历数组并从每个数组中创建 Ember 对象。我认为 Ember 中没有任何内置功能可以为您做到这一点。
        • @Qrilka 不知道这是怎么回事...我已经更正了链接。
        • @RoyDaniels 如何仅在特定键处渲染对象,比如说 0?数组表示法似乎在模板中不起作用。
        • @Rajat 这应该是一个单独的问题,因为它实际上与原始问题或解决方案没有任何关系。不过 StackOverflow 的礼仪就够了,看看this jsFiddle
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-20
        • 1970-01-01
        • 2023-03-07
        • 1970-01-01
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多