【问题标题】:Ember.js computed property filter hasMany arrayEmber.js 计算属性过滤器 hasMany 数组
【发布时间】:2014-10-08 22:40:39
【问题描述】:

我正在尝试过滤 ember-data 'hasMany' 字段的内容。我的模型有一些子问题,我想将其过滤到控制器上的属性“childOptions”中并使用

显示在模板中
{{#each childOptions}}stuff{{/each}}

当我把它放在我的控制器上时,它可以工作,并且每个都会迭代适当的值:

childOptions: Ember.computed.filterBy('model.subquestions', 'surveyQuestionType.name', 'childOption'),

但是当我这样做时,什么都没有显示。

childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType.name') === 'childOption';
}),

“surveyQuestionType”是一个 DS.belongsTo,存在于“子问题”的模型中,并且具有“名称”属性。

我想了解为什么 'filterBy' 方法有效,而 'filter' 方法无效(这样我以后可以使用 'filter' 进行更复杂的查询)。我认为这与 Promise 以及我在 filter 函数中使用的 subquestion.get('property') 语法有关。

编辑:

这是模型:

App.SurveyQuestion = DS.Model.extend(Ember.Validations.Mixin, {
    surveyQuestionType: DS.belongsTo('surveyQuestionType', { async: true }),
    display: DS.belongsTo('surveyQuestionDisplay', { async: true, inverse: 'surveyQuestion' }),
    sortOrder: DS.attr('number'),
    parent: DS.belongsTo('surveyQuestion', { async: true, inverse: 'subquestions' }),
    parentDependencyCriteria: DS.attr('string'),
    required: DS.attr('boolean'),
    surveySections: DS.hasMany('surveySectionQuestion', { async: true, inverse: 'surveyQuestion' }),
    subquestions: DS.hasMany('surveyQuestion', { async: true, inverse: 'parent' })
});

【问题讨论】:

  • subquestion.get('surveyQuestionType.name') 返回undefined,我很确定这是问题所在,但我不知道如何解决!如果我在模板中做一个简单的{{#each subquestions}}{{surveyQuestionType.name}}{{/each}},我可以看到该属性就好了。

标签: ember.js ember-data


【解决方案1】:

我在自己的工作中发现此类问题所花费的时间比我愿意承认的要多,但幸运的是,解决方案很简单。在您的 DS.Model 定义中,surveyQuestionTypebelongsTo{async: true} 的关系吗?如果是这样,那是你的问题。

当您在DS.Model 中将关系设置为{async: true} 时,您可以将其视为实际上设置了一个承诺,您最终将获得该属性。这是有道理的并且变得直观,但它没有很好地记录!

Promise 对于初学者来说尤其棘手,因为无论 surveyQuestionType 是具体值还是 Promise,Handlebars 模板都会透明地处理 {{surveyQuestionType.name}}。这会让初学者感到困惑,因为乍一看你无法判断 Handlebars 是呈现具体值还是承诺。

当您处理一个 Promise 时,您可以在其 content 属性中直接访问该 Promise 解析为的内容。事实上,您甚至可以设置 content 属性。但请注意这一点,因为直接读取/写入 content 属性对 promise 可能具有的任何未决操作没有影响。因此,如果在您写入其content 值时,promise 仍处于未决状态,则一旦解决,您的写入将被覆盖。

当我添加新实体并需要填充承诺关系时,我直接写入content 属性。这是有道理的,但如果我正在读取一个值,我需要找到一些方法来保证在我读取 content 属性时承诺已经解决......或者,我可以让 Handlebars 处理这个直接,知道对于纯显示逻辑我不关心 150 毫秒的延迟。

无论如何,如果以上所有内容都适用于您的问题,那么您可以通过以下方式编辑代码以使其正常工作:

childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType.content.name') === 'childOption';
})

更新 #1: 我认为我没有仔细访问 content,这违反了我自己的建议。有关调试的信息,请参阅我的 cmets,您也可以试试这个:

childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType').then( function( model ) {
       return model.get('name') === 'childOption';
    });
})

更新 #2: 请参阅下面的我的 cmets,尤其是 https://github.com/emberjs/data/issues/1865。事实证明这是一个更棘手的问题,我欢迎其他人提出意见,以澄清这里的最佳方法。

我已经在自己的代码中通过处理上游承诺解决了这个问题,这样我就可以直接访问content 属性或在我的过滤器中根本不处理承诺。

【讨论】:

  • 感谢您的解释,您对async: true 的看法是正确的。不过,您的答案并不完全奏效。可能 subquestions 属性也是一个 Promise 数组。另外,在使用Ember.computed.filter 时是否不需要添加.property()?理想情况下,我想要在承诺解决后过滤的东西,对吧?
  • 回复:.property(),您是对的,感谢您指出这一点。我会更新我的答案。稍后会回复其他问题。
  • Re: 这不行,我有两个想法。 (1) 准确了解您正在处理的每个实体是什么很有帮助。所以,试试console.log(this.get('model.subquestions').toString()) 这会告诉你这是一个承诺还是具体的价值。你还应该看看优秀的eviltrout.com/2014/08/16/debugging-ember-js.html。 (2) 我可能在原始答案中犯了一个错误,因为我从 Promise 访问了内容,但是该代码不会等到 Promise 被解析后才读取该值。查看更新的答案。对于原始回复中的错误,我们深表歉意。
  • then 中返回一个值没有任何作用。这将最终过滤承诺的价值(这将永远是真实的)。
  • 好的,在过滤器中使用异步结果比我最初意识到的要棘手得多。见github.com/emberjs/data/issues/1865。就个人而言,我已经通过在上游进一步解决我的承诺来解决这个问题。我的回答解决了部分问题,但没有给你完整的解决方案。
【解决方案2】:

从 ember-data 1.0.0-beta.11 开始,promise 似乎运行得更顺畅了,我在这方面取得了成功(我实际上为我的原始问题采用了不同的方法,但在类似情况下使用了此代码) :

childOptions: function() {
    var subquestions = this.get('subquestions');
    if (subquestions) {
        return subquestions.filter(function(subquestion) {    
            var surveyQuestion = subquestion.get('surveyQuestion');
            return (surveyQuestion && surveyQuestion.get('name') === 'childOptions');
        });
    }
}.property('subquestions.@each.surveyQuestion')

.property('subquestions.@each.surveyQuestion') 会在 surveyQuestion 承诺解决时更新属性。如果您输入一些输出,您将看到最初调用该属性并且subquestions 将为空。

【讨论】:

  • 忽略“if (subquestions)”并在每次使用该函数的地方添加一个 .property("childOptions")。没有测试它,但应该可以工作。我使用 .any 而不是 filter 并且它有效。
猜你喜欢
  • 1970-01-01
  • 2015-02-26
  • 2015-02-09
  • 2013-06-29
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
  • 2013-11-29
  • 1970-01-01
相关资源
最近更新 更多