Javascript Ember.js:如何对这个例子建模?

Javascript Ember.js:如何对这个例子建模?,javascript,architecture,ember.js,Javascript,Architecture,Ember.js,我正在试图找出正确的Ember.js方法来建模这个项目,例如,需要什么模型、路线和控制器 我的需求可以安全地减少到: 项目及其选项 项目有一个选项集合 选项有自己的属性 项目具有仪表板将使用的其他属性(选项除外) 仪表板 仪表板没有自己的任何数据 仪表板需要观察所有项目和选项,并更新对其属性的分析 导航 { "Items" : [ { "Item" : { "nid" : "3", "title" : "Hydro",

我正在试图找出正确的Ember.js方法来建模这个项目,例如,需要什么模型、路线和控制器

我的需求可以安全地减少到:

项目及其选项

  • 项目有一个选项集合
  • 选项有自己的属性
  • 项目具有仪表板将使用的其他属性(选项除外)
仪表板

  • 仪表板没有自己的任何数据
  • 仪表板需要观察所有项目和选项,并更新对其属性的分析
导航

{
  "Items" : [
    {
      "Item" : {
        "nid" : "3",
        "title" : "Hydro",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/hydro.jpg",
        "properties" : "Baseload, Intermittent",
                "values" : {
                    "Cost" : {
                        "price" : "6",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "56"
                    }
                },
                "options" : {
                    "1" : {
                        "price" : "1512",
                        "quantity" : "10000"
                    },
                    "12" : {
                        "price" : "825",
                        "quantity" : "20000"
                    },
                    "11" : {
                        "price" : "550",
                        "quantity" : "50000"
                    }
                }
      }
    },
    {
      "Item" : {
        "nid" : "4",
        "title" : "Nuclear",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/nuclear.jpg",
        "id" : "",
        "properties" : "Baseload, Predictable",
                "values" : {
                    "Cost" : {
                        "price" : "8",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "21"
                    }
                },
                "options" : {
                    "4" : {
                        "price" : "825",
                        "quantity" : "10000"
                    },
                    "13" : {
                        "price" : "411",
                        "quantity" : "15000"
                    }
                }
      }
    },
    {
      "Item" : {
        "nid" : "5",
        "title" : "Natural Gas",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/gas.jpg",
        "id" : "9",
        "properties" : "Baseload, Predictable",
                "values" : {
                    "Cost" : {
                        "price" : "5",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "24"
                    }
                },
                "options" : {
                    "7" : {
                        "price" : "400",
                        "quantity" : "50000"
                    },
                    "10" : {
                        "price" : "600",
                        "quantity" : "100000"
                    }
                }
      }
    }
  ]
}
  • 几乎没有
  • 这将出现在一个“页面”上,但将来可能会添加少量页面/弹出窗口
  • 我希望能够保存并重新填充给定状态(例如,所选选项ID的列表)
数据

  • 数据将通过单个json调用加载一次
  • 应用程序逻辑将在Ember中单独在客户端完成-业务逻辑没有ajax
  • 只有在用户保存状态时,才会与服务器联系
那么,在余烬中,这将是如何构建的呢

我曾经试着自己做过一次,但这是我第一次尝试,结果是一个非常丑陋的设置。我想看看有余烬经验的人是如何做到这一点的:

jsBin模型()

我已经创建了一系列把手模板,但没有尝试过应该存在哪些模型以及需要哪些控制器。。

Json

{
  "Items" : [
    {
      "Item" : {
        "nid" : "3",
        "title" : "Hydro",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/hydro.jpg",
        "properties" : "Baseload, Intermittent",
                "values" : {
                    "Cost" : {
                        "price" : "6",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "56"
                    }
                },
                "options" : {
                    "1" : {
                        "price" : "1512",
                        "quantity" : "10000"
                    },
                    "12" : {
                        "price" : "825",
                        "quantity" : "20000"
                    },
                    "11" : {
                        "price" : "550",
                        "quantity" : "50000"
                    }
                }
      }
    },
    {
      "Item" : {
        "nid" : "4",
        "title" : "Nuclear",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/nuclear.jpg",
        "id" : "",
        "properties" : "Baseload, Predictable",
                "values" : {
                    "Cost" : {
                        "price" : "8",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "21"
                    }
                },
                "options" : {
                    "4" : {
                        "price" : "825",
                        "quantity" : "10000"
                    },
                    "13" : {
                        "price" : "411",
                        "quantity" : "15000"
                    }
                }
      }
    },
    {
      "Item" : {
        "nid" : "5",
        "title" : "Natural Gas",
        "image" : "http://bpf.vm/sites/default/files/bpf_things/gas.jpg",
        "id" : "9",
        "properties" : "Baseload, Predictable",
                "values" : {
                    "Cost" : {
                        "price" : "5",
                        "quantity" : null
                    },
                    "Percent of Portfolio" : {
                        "price" : null,
                        "quantity" : "24"
                    }
                },
                "options" : {
                    "7" : {
                        "price" : "400",
                        "quantity" : "50000"
                    },
                    "10" : {
                        "price" : "600",
                        "quantity" : "100000"
                    }
                }
      }
    }
  ]
}

以下是答案的开头:

型号

我想我这里只需要三种型号。仪表板是此应用程序中的主要角色,但它没有自己的任何数据

  • 项目模型-保存项目的所有信息
  • 选项模型-保存选项的所有信息
  • 显示模式-保存一组选定的选项ID,这些ID可以发送到服务器并保存,也可以用于将应用返回到特定状态
控制器

早些时候,我完全不了解ArrayController的概念。通常,任何集合都需要ArrayController来表示,而不是普通的ember ObjectController。我的“项目”需要一个,但我认为“选项”不会,因为选项是项目的子项,可以使用项目/项目作为代理

  • 仪表板-我猜这将是一个结实的仪表板,因为控制器需要处理所有项目和集合
  • 项目-因为有很多项目,我们需要一个ArrayController
  • 项目-当项目的状态发生变化时,项目需要对其选项进行一些简单的分析
  • 选项-选项至少需要响应单击操作
模板

此处的缩进表示呈现其他模板的模板。例如,我的显示模板包含
{{render dashboard}}
{{render items}}

  • 应用程序-从技术上讲,应用程序根目录会重定向到显示器(这可能不是必需的)
    • 显示-基本上是我的应用程序的根目录。
      • 仪表板-提供项目/选项视觉分析的区域
      • 项目-渲染每个项目
        • 选项-呈现每个项目的选项
路线

这仍然很模糊。路由似乎扮演着许多角色(将URL映射到模型,为控制器设置模型,可能还有其他的东西??)。目前,我能想到的唯一url是:

  • 显示-由于我的“显示”表示应用程序快照(例如,保存的版本),因此需要在App.Router.map中指定它
其他路线:

  • 应用程序路线
    • setupController
      :将控制器设置为空白/保存的显示
  • 索引路由
    • 重定向
      :只重定向到显示路径(基本上是应用程序的根目录)
  • 显示路线
    • 模型
      :将给定显示设置为模型
    • afterModel
      :加载显示器指定的项目
我想就这些。这是一个简单的应用程序,一旦我加载了用于显示的项目,应用程序就会更改屏幕的显示。有用户选择,但它们是布尔标志(例如在项目上设置isSelected会改变仪表板显示的数据)-这些选择不需要任何导航。

我设置了一个小JSBin

好的,在聊了一会儿,再看了一会儿之后,下面是我对如何简化的想法:

您只有一个URL,因此我现在只使用一个路由和一个控制器

数据模型非常简单,因为它是完全分层的:

显示器有许多, 一个项目有许多选项

而且,由于您一次只查看一个显示器,因此根本不需要将显示器作为模型。如果您的应用程序不断发展,并且您同时拥有多个显示,那么实现一个显示模型并通过该模型执行所有JSON请求是有意义的

我将实现一个单一的路由和控制器:

App.Router.map(function() {
     this.resource('display', path: { 'display/:id' });
});

App.DisplayRoute = Ember.Route.extend({
    model: function(params) {
        return App.Item.find(params._id);
    }
});
DisplayController可以完全访问其所有项目,因为它们被设置为其型号

我认为你现在只需要一个模板,你可以在以后把它们分割成多个部分
App.DisplayController = Ember.ArrayController.extend({
    // add computed properties here..

    actions: {
        selectOption: function(option) {
            option.set('isSelected', true);
        }
    }

});
App.Item = Ember.Option.extend({
    selected: false
    // add computed properties here
});

App.Item.reopenClass({

    // retrieves the items from the server

    find: function(displayId) {

        var url = "/game/json" + displayId;

        var items = new Ember.A();

        Ember.$.getJSON().success(function(data) {
            data.items.forEach(function(jsonItem) {

                var item = Ember.Item.create({
                    nid: jsonItem.nid,
                    title: jsonItem.title,
                    image: jsonItem.image
                });

                item.set('options', new Ember.A());

                jsonItem.options.forEach(function(option) {
                    var option = Ember.Option.create({
                        // set option properties
                    });
                    emberItem.get('options').pushObject(option);
                })

            })

        });

        return items;
    }
});