8

我试图弄清楚为这个项目建模的正确 Ember.js 方法是什么,例如。需要什么模型、路线和控制器。 我已经启动了一个 jsBin 来工作

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

项目及其选项

  • 项目有一系列选项
  • 选项有自己的属性
  • 项目具有仪表板将使用的其他属性(除了选项之外)

仪表板

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

导航

  • 几乎没有
  • 这将出现在一个“页面”上,但将来可能会添加少量页面/弹出窗口
  • 我希望能够保存和重新填充给定的状态(例如,所选选项 id 的列表)

数据

  • 数据将通过单个 json 调用加载一次
  • 应用程序逻辑将仅在 Ember 中的客户端完成 - 业务逻辑没有 ajax
  • 与服务器的唯一后续联系将是如果/何时用户保存状态

那么这将如何在 Ember 中构建呢?

我曾经尝试过自己做一次,但这是我的第一次尝试,最终我得到了一个非常丑陋的设置。我想看看有 Ember 经验的人会如何处理这个问题:

jsBin 样机(链接

我已经创建了一系列车把模板,但还没有确定应该存在哪些模型以及需要哪些控制器。 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"
                    }
                }
      }
    }
  ]
}
4

2 回答 2

3

我放了一个小的 JSBin http://jsbin.com/IdAXuMar/5/edit

好的,所以在进行了一次聊天并仔细查看之后,以下是我对如何简化这一点的想法:

您只有一个 URL,因此我现在只使用一个 Route 和一个 Controller。

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

一个Display有很多Item,一个Item有很多Options

而且因为您一次只看一个显示器,所以您根本不需要显示器作为模型。但是,如果您的应用程序不断发展并且您同时拥有多个 Display,那么实现一个 Display 模型并通过该模型执行所有 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 对其所有项目具有完全访问权限,因为它们被设置为它的模型。

我认为您现在只需要一个模板,如果它变得失控,您可以稍后将它们拆分为多个部分。

<script type="text/x-handlebars" data-template-name="display">    
  {{#each model}}
    <!-- access on every item here -->


    {{#each option}}
      {{#if isSelected}}
        this option is selected
      {{/if}}
      <!-- access on every option here -->

      <a {{action selectOption this}} href=''> Select this option</a>

    {{/each}}
  {{/each}}
</script>

请注意 selectOption 操作:当调用此选项并传递选项时,您可以直接在选项本身上设置选定状态,这将立即反映在视图中。

App.DisplayController = Ember.ArrayController.extend({
    // add computed properties here..

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

});

要从服务器获取项目,您可以调用 App.Item.find() 然后传递显示的 ID。这不是 100% 的惯例,因为您应该在这里传递项目的 id,但我认为为此目的是可以的。所以这个方法看起来像

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

我希望这可以帮助您入门,也许可以更轻松地将您的概念转移到 Ember。如果您对例如如何将所有内容保存回服务器有疑问,请拍摄:)

于 2013-11-22T19:53:40.353 回答
2

这是答案的开头:

楷模

我想我这里只需要三个模型。仪表板是这个应用程序的主要参与者,但它没有任何自己的数据。

  • 项目模型- 保存项目的所有信息
  • 期权模型- 保存期权的所有信息
  • 显示模型- 包含一组选定的选项 ID,它们可以发送到服务器并保存,也可以用于将应用程序返回到特定状态

控制器

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

  • 仪表板- 我猜这将是一个强大的,因为控制器需要处理所有项目和集合
  • 项目- 因为有很多项目,我们将需要一个 ArrayController 为它们
  • Item - 当状态改变时,item 需要对其选项做一些简单的分析
  • 选项- 选项至少需要响应点击操作

模板

这里的缩进表示渲染其他模板的模板。例如,我的 Display 模板包含{{render dashboard}}and {{render items}}

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

路线

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

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

其他路线:

  • 申请路线
    • setupController:将控制器设置为空白/已保存的显示
  • 索引路由
    • redirect: 只是重定向到显示路由(本质上是应用程序的根目录)
  • 显示路由
    • model:将给定的显示设置为模型
    • afterModel:加载显示指定的项目

我想就是这样。这是一个简单的应用程序,一旦我为显示加载了项目,那么该应用程序只会更改屏幕的显示。有用户选择,但它们是布尔标志(例如,在项目上设置 isSelected 应该会改变仪表板显示的数据)——这些选择不需要任何导航。

于 2013-11-15T20:46:09.633 回答