【问题标题】:Route's Model Hook with Ember Data "filter" not loading dependent computed property带有 Ember 数据“过滤器”的 Route 模型挂钩未加载相关计算属性
【发布时间】:2014-06-23 20:52:18
【问题描述】:

希望你能帮助我! :)

我的问题是我有一个看起来像这样的路线,我希望它填充一个项目列表......即“请只标记那些”,但它没有:

App.TaggedItemsListRoute = App.ItemsRoute.extend({
  model: function() {
    var store = this.get("store");
    var storePromise = store.find("item", { has_tags: true });
    var filtered = store.filter("item", function(item) {
      return item.get("hasTags");
    });
    return storePromise.then(function(response) {
      return filtered;
    });
  }
});

现在......这只是简单的不起作用,因为“hasTags”返回false,因为它依赖于“tags”,它返回一个暂时为空的ManyArray,因为它还没有解析(参见下面的模型)。这对我来说似乎很糟糕。它的意思是“嘿,我什么都没有!”但我想要它说的是“请稍后重新计算我”并且过滤器正在寻找一个布尔值,但我想要传递的是“嘿,在所有 hasTags 都解决之前不要解析过滤器”或至少重新计算 it 传递的 ManyArray。

如果我只是将一个承诺作为过滤器的返回值传回,那么它有点工作......

return item.get("tags").then(function(tags){ return item.get("hasTags"); });

除了它实际上不是,因为过滤器正在获得一个 Promise,但显然它不知道 Promise,所以当它寻找一个布尔值时,它会得到一个它评估为 true 的 Promise,然后它几乎显示了所有列表中的项目。这不是问题,直到我去不同的路线购买物品,比如说上面有所有物品,然后回来......然后BAM它里面有所有物品......嗯......

以下是我暂时“解决”它的方法......即它仍然是错误的,但我可以忍受它......

App.TaggedItemsListRoute = App.ItemsRoute.extend({
  model: function() {
    var store = this.get("store");
    var storePromise = store.find("item", { has_tags: true });
    var filtered = store.filter("item", function(item) {
      var tags = item.get("tags");
      if tags.get("isFulfilled") {
        return item.get("hasTags");
      } else {
        return tags.then(function() {
          return item.get("hasTags");
        });
      }
    });
    return storePromise.then(function(response) {
      return filtered;
    });
  }
});

我认为在这个阶段真正解决这个问题的唯一方法是使用 RSVP.all...有什么想法吗?

实际上我还没有尝试过的一件事我现在可能会尝试使用 setupController 进行过滤。唯一的麻烦是所有项目都会被加载到列表中,然后在大约 1 秒后视觉上“跳回”到过滤状态。好痛!

模型

我的 Ember 应用程序(Ember 1.5.1)有两个模型(Ember Data beta7):项目和标签。项目有很多标签。

App.Item = DS.Model.extend({
  tags: DS.hasMany("tag", inverse: "item", async: true),
  hasTags: function() {
    return !Em.isEmpty(this.get("tags"));
  }.property("tags")
});

App.Tag = DS.Model.extend(
  item: DS.belongsTo("item", inverse: "tags"),
  hasItem: function() {
    return !Em.isEmpty(this.get("item"))
  }.property("item")
);

如果我将模型更改为以下,当我转到上面的路线时,它实际上会在日志中打印一些内容,因此它正在履行承诺。

App.Item = DS.Model.extend({
  tags: DS.hasMany("tag", inverse: "item", async: true),
  hasTags: function() {
    this.get("tags").then(function(tags) {
      console.log("The tags are loding if this is printed");
    });
    return !Em.isEmpty(this.get("tags"));
  }.property("tags")
});

这是来自Ember Data hasMany async observed property "simple" issue 的一个衍生问题,因为我没有真正很好地解释我的问题,实际上是在问错误的问题。我最初认为我可以修改我的模型“hasTags”属性以在我的 Route 上下文中正确运行,但我现在认为这不会正常工作......

【问题讨论】:

    标签: javascript ember.js ember-data


    【解决方案1】:

    这似乎是RSVP.all 的完美候选。顺便说一句,如果您想简要了解 RSVP,我几周前就进行了一次演讲(不要太关注它,披萨到了一半,我饿了,http://www.youtube.com/watch?v=8WXgm4_V85E)。无论如何,您的过滤器显然取决于在执行之前解决的标签集合承诺。因此,在执行过滤器之前等待解决这些问题是合适的。

    App.TaggedItemsListRoute = App.ItemsRoute.extend({
      model: function() {
        var store = this.get("store");
        return store.find("item", { has_tags: true }).then(function(items){
             var tagPromises = items.getEach('tags');
             return Ember.RSVP.all(tagPromises).then(function(tagCollections){
                 // at this point all tags have been received
                 // build your filter, and resolve that
                 return store.filter("item", function(item) {
                    return item.get("hasTags");
                 });
             });
        });
      }
    });
    

    使用与颜色类似的想法的示例(我仅在关系具有 3 种关联颜色时才显示它)

    http://emberjs.jsbin.com/OxIDiVU/454/edit

    另外说明,如果您希望此挂钩立即解决,然后神奇地填充,您可以作弊并返回一个数组,然后在服务器返回结果后填充该数组,从而允许您的应用看起来它的反应超级快(通过在页面上绘制一些东西,然后随着结果的涌现而神奇地填充)。

    App.TaggedItemsListRoute = App.ItemsRoute.extend({
      model: function() {
        var store = this.get("store"),
            quickResults = [];
        store.find("item", { has_tags: true }).then(function(items){
             var tagPromises = items.getEach('tags');
             return Ember.RSVP.all(tagPromises).then(function(tagCollections){
                 // at this point all tags have been received
                 // build your filter, and resolve that
                 return store.filter("item", function(item) {
                    return item.get("hasTags");
                 });
             });
        }).then(function(filterResults){
           filterResults.forEach(function(item){
             quickResults.pushObject(item);
           });
        });
    
        return quickResults;
      }
    });
    

    快速结果示例,立即返回(我仅在关系具有 3 种关联颜色时显示)

    http://emberjs.jsbin.com/OxIDiVU/455/edit

    【讨论】:

    • 感谢 kingpin2k。我爱你 :) 顺便说一句,这个完全有效的解决方案到底有多烂?我们必须像这样编写代码是最大的失败。 Javascript就是这样一个狗蛋。 - 此外,我正在尝试使用模型挂钩的阻塞 UI(即我的应用程序中有一个“等待数据”模板,所以我并不特别想要“quickResults”)。知道“是的,使用 RSVP.all 就足够了。我知道如何使用它,所以我会去使用它:) 我会看你的视频 :) 谢谢!
    • 一旦我实现了它并且它可以工作,我会将此作为正确答案。 :)
    • 感谢您的所有帮助,顺便说一句,您可能会做非异步标签,因为无论如何您都必须等待它们全部获取,少一个请求。
    • 我发现在类似的情况下,我定义了一个自定义 tagsLength 属性,它代理 data.tags.length 以避免请求所有标签。我认为问题/情况的根源是github.com/emberjs/data/issues/586。
    • 是的,这是使用异步关系的已知限制。长度和 id 不一定需要对服务器进行回调,但是当前的实现在触摸记录的引用时会延迟加载记录。目前大多数人都在使用通常不推荐的内部属性来破解。
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 2020-12-21
    相关资源
    最近更新 更多