学习Ember.js-坚持多对多的关系

时间:2013-10-29 15:41:20

标签: javascript ember.js ember-data handlebars.js

要学习Ember.js,我开始编写一个小书签应用程序。我现在正在努力解决与错误数据处理相关的问题。

解释申请

  • 用户可以添加标签
  • 用户可以添加指向所选标签的链接
  • 标签可以有n个链接
  • 链接可以有n个标签
  • 通过选择关联的标签显示链接

问题
链接数据不是写入数据存储的。因此,覆盖了由于选择更改而导致的链接模型的本地更新。此外,稍后实现真正的持久性也行不通。

缩小问题范围

在IndexRoute中我初始化模型:

model: function(params) {
    return {
        labels: this.get("store").find("label"),
        // TODO: this is probably wrong.
        links: Ember.A()
    };
}

一方面,我从数据存储中获取标签数据。另一方面,我使用空的ember数组初始化链接数据。

在我看来,这是故障的根源,但我不知道如何正确实施。 我试图用存储适配器的虚假引用替换它:

this.get("store").find("label").filter("_")

这既不对,也不正常。然后它继续到我无法使用存储适配器更新记录的程度:

// TODO: this is probably wrong.
this.get("links").addObject({
    name: linkName,
    url: linkUrl,
    labels: this.selectedLabels
});
/*store.push("link", {
    name: newLink,
    url: linkUrl,
    labels: this.selectedLabels
});*/

等等。

Jsbin:http://jsbin.com/ucanam/1751/edit

如何正确存储链接数据,以便更改控制器的本地数据不会破坏应用程序?

修改
我想我在你的建议中发现了我的概念错误。这是否意味着我总是要处理本地副本?

var link = this.get("model");
link.deleteRecord();
link.save().then(function(link) {
    var indexController = this.get('controllers.index');
    indexController.get("links").removeObject(link);
});

在您的示例中,您使用了将对象添加到控制器的承诺。在此代码示例中,承诺永远不会实现 - 因此它只能在没有。

的情况下工作

同样在LabelController中,remove方法也应删除相关链接。如果我在forEach循环中使用deleteRecord它只删除一个标签然后以某种方式使循环退出。这是故意还是我犯了错误?

我已经更新了你的JsBin http://jsbin.com/ucanam/1987/edit

2 个答案:

答案 0 :(得分:3)

我修改了你的JSbin http://jsbin.com/ucanam/1975/

如果您想要保留记录,则必须使用 createRecord()在商店中创建它们,然后保存()。新的newLink功能

    newLink: function() {
        var store = this.get("store"),
            linkName = this.get("linkName"),
            linkUrl = this.get("linkUrl"),
            links = this.get("links"),
            selectedLabels = this.get('selectedLabels');

        if(selectedLabels.get('length') > 0) {
            if(linkName.length > 0 && linkUrl.length > 0) {
              var newLink = store.createRecord('link',
                {
                    name: linkName,
                    url: linkUrl
                });
              selectedLabels.forEach(function(label){
                newLink.get('labels').addObject(label);
              });
              newLink.save().then(function(link){
                links.addObject(link);
              });
              this.set("linkName", "");
              this.set("linkUrl", "");
            }
        } else {
            alert("You have to select a label!");
        }
    },

对于删除记录,使用forEach 存在问题,因为查找商店的结果是实时数组。您可以在GitHub https://github.com/emberjs/data/issues/772中看到此讨论。 所以你的删除标签功能应该是(注意使用 toArray()来制作实时数组的静态副本)

    remove: function() {
        var indexController = this.get('controllers.index'),
            label = this.get('model'),
            linksPromise = this.get('store').find('link');

        linksPromise.then(function(links){
            links.toArray().forEach(function(link){
                var linkLabels = link.get('labels'),
                    linkLabelsIds = linkLabels.mapProperty('id');

                if(linkLabelsIds.contains(label.get("id"))) {
                    if(linkLabelsIds.get("length") == 1) {
                        console.log("delete link: "+link.get("name"));
                        indexController.get("links").removeObject(link);
                        link.deleteRecord();
                        link.save();
                    }
                }
            });

            label.deleteRecord();
            label.save();
        });
    }

最后注意事项,不要忘记在删除记录后对记录进行保存(),jsBin在这里:http://jsbin.com/ucanam/1989/

答案 1 :(得分:1)

您是否定义了模型?

App.Label = DS.Model.extend({
    title: DS.attr('string'),
    links: DS.hasMany('link')
});

App.Link = DS.Model.extend({
    name: DS.attr('string'),
    url: DS.attr('string'),
    labels: DS.hasMany('label')
});

App.IndexRoute = Ember.Route.extend({
    model: function() {
        this.store.find('label')
    }
});

App.LabelController = Ember.ObjectController.extend({
    actions:
        <!-- functions here -->
});

<script type='text/handlebars' data-template-name="index">
    {{#each label in model itemController='label'}}
        {{label.title}}
            {{#each link in label.links}}
                {{link.title}}
            {{/each}}
    {{/each}}
</script>