【问题标题】:Ember.js: how to model this example?Ember.js:如何建模这个例子?
【发布时间】:2013-11-14 20:13:09
【问题描述】:

我正在尝试找出正确的 Ember.js 方法来为这个项目建模,例如。需要什么模型、路线和控制器。 I have started a jsBin to work from.

我的要求可以安全地简化为:

项目及其选项

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

仪表板

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

导航

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

数据

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

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

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

jsBin 模型 (link)

我已经创建了一系列车把模板,但还没有确定应该存在哪些模型以及需要哪些控制器。

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

【问题讨论】:

  • 您能否更具体地说明建模的含义?您的意思是如何设计控制器、网址等?或者你的意思是数据模型?如果是前者,看看你的“丑陋”设置会很有帮助。
  • 更新了帖子,包含更多详细信息、指向 jsBin 的链接(仅限模板 - 无法移植我当前的工作)以及更新的屏幕截图。
  • 关于如何与 Conrad 构建此应用程序的非常有帮助的对话:chat.stackoverflow.com/rooms/41721/…

标签: javascript architecture ember.js


【解决方案1】:

我放了一个小JSBinhttp://jsbin.com/IdAXuMar/5/edit

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

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

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

一个Display有很多Items, 一个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。如果您对例如如何将所有内容保存回服务器有疑问,请拍摄:)

【讨论】:

    【解决方案2】:

    这是答案的开头:

    模型

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

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

    控制器

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

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

    模板

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

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

    路线

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

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

    其他路线:

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

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

    【讨论】:

    • 我在这里看到的一个问题是我并没有真正使用项目集合的概念。到目前为止,我一直在考虑使用 {{each}} 来渲染它们,并且根本没有考虑过对项目集合进行路由。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 2012-06-02
    相关资源
    最近更新 更多