【问题标题】:Ember computed property for retrieving one record out of a hasMany relationship?用于从 hasMany 关系中检索一条记录的 Ember 计算属性?
【发布时间】:2017-07-08 01:48:57
【问题描述】:

这是我的情况,简化:

// model/price-source.js

export default DS.Model.extend({
  price: DS.attr('number'),
  product: DS.belongsTo('product')
)};

// model/product.js

export default DS.Model.extend({
  priceSources: DS.hasMany('price-source')
)};

在我的产品模板中,我希望能够简单地引用价格最低的来源,如下所示:

// templates/products.hbs

{{#each model as |product|}}
<span>{{product.cheapestSource.price}} €</span>
{{/each}}

我将如何设置最便宜的Source 计算属性?我想我必须做这样的事情:

// model/product.js

  cheapestSource: Ember.computed('priceSources', function() {
    let sources = this.get('priceSources');
    let cheapest = sources.get('firstObject');

    // iterate over sources and set cheapest to whichever has the lowest price

    return cheapest;
  })

问题是,我不知道如何循环遍历 hasMany 关系(除了使用把手 {{#each}} 帮助器),以及计算属性是否甚至可以包含来自另一个模型的单个 Ember 数据记录. sources.@each 是否以某种方式参与其中,如果是,如何?

感谢任何帮助和想法,谢谢。

【问题讨论】:

    标签: ember.js ember-data has-many computed-properties


    【解决方案1】:

    我通过将 priceSources 排序到计算属性 sortedPrices 中,然后在模板中调用 sortedPrices 的 firstObject 来使其工作。很快就会用实际的解决方案编辑这篇文章。

    测试需要很长时间,因为我没有意识到注释掉把手块会破坏其中的 html 呈现。给自己的注意...


    编辑:这样做了:

    export default DS.Model.extend({
      priceSources: DS.hasMany('price-source'),
      sortProperties: ['price:asc'],
      sortedSources: Ember.computed.sort('priceSources', 'sortProperties')
    });
    

    然后在模板中:

    <span>{{product.sortedSources.firstObject.price}} €</span>
    

    工作正常,无需大量代码。

    【讨论】:

      【解决方案2】:

      您可以在需要使用最便宜来源的控制器上执行此操作。

         cheapestSource: Ember.computed('priceSources', function() {
              let sources = this.get('priceSources');
              let cheapest = sources.get('firstObject');   
              let array = sources.mapBy("price");
              let min = array.reduce(function(a, b, i, array) {return Math.min(a,b)});
              sources.forEach(function(source){
                if (source.get("price") == min){
                  cheapest = source;
                } 
             });
          return cheapest;
          })
      

      模型很难实现你想要的,这就是为什么使用一个计算的并且在模板渲染之后计算成为你需要的对象的原因之一。

      cheapestSource: Ember.computed('priceSources', function() {
              let product = this;
              this.get('priceSources').then((sources)=>{
              let array = sources.mapBy("price");
              if(array.length>0){
              let min = array.reduce(function(a, b, i, array) {return Math.min(a,b)});
              sources.forEach(function(source){
                if (source.get("price") == min){
                  product.set("cheapestSource", source);
                } 
             });
            }
          });
        })
      

      当我遇到这样的问题时,我在 Rails 上使用活动模型适配器并在我的自定义序列化程序中返回例如最便宜的SourcePrice 作为产品的一部分,然后在 Ember 产品模型中添加最便宜的SourcePrice 和模板 {{product.cheapestSourcePrice}} 你不要@ 987654324@t 控制服务器然后这样做。在将 source 设置为cheesesetSource 计算之后的另一件事就是刷新。如果您需要它保持计算状态,您必须在模型上再添加一个属性,然后设置他 insted 示例

      cheapestSource2: DS.attr()

      这将允许它成为一个对象

      product.set("cheapestSource2", source);

      然后在模板中 {{product.cheapestSource}}{{product.cheapestSource2.price}}

      你调用的第一个属性在那里,所以计算被调用。

      【讨论】:

      • 我正在阅读这份relationships as promises 指南。我们可以像您一样直接访问它吗?如果可能的话,请在您的回答中解释..只是为了我的学习。谢谢。还有依赖键priceSources.@each.price 可能有用。您阅读后我将删除我的评论
      • 我在控制器上做了这个,现在我明白你为什么问这个问题了,他是在一个模型中做的,谢谢。
      • @Sedad.Kosovac 不幸的是,没有显示 priceSource 对象(在 Ember Inspector 中)。我没有收到错误。我试过return this.get('priceSources').get('firstObject'),也试过return this.get('priceSources.firstObject'),但没有。由于无论如何我都需要对源进行排序,因此获得最便宜的源的更好方法可能是先排序,然后在 sortedSources 计算属性中检索 firstObject。
      • 我为模型编辑了我的答案,我认为你不会在模型的计算属性中对其进行排序。
      • @Sedad.Kosovac 谢谢,我会尝试一下您的解决方案。我让它以不同的方式工作,见下文。
      【解决方案3】:

      如果你有时间也试试这个解决方案。 this.get('priceSources') 它返回 Promise,因此您需要在 then 方法中访问结果并将其包装在 DS.PromiseObject 中,以便您可以像访问模板中的普通对象一样访问它。

      cheapestSource: Ember.computed('priceSources.@each.price', function() {
              return DS.PromiseObject.create({
                  promise: this.get('priceSources').then(sources => {
                      let resultObj = {}
                          //sources is normal array you can apply your logic and set resultObj
                      return resultObj;
                  })
              });
          })
      

      【讨论】:

      • 这应该进入组件(或控制器)或模型吗?在模型中尝试过,得到了这个:Uncaught TypeError: this.get(...).then is not a function。我认为这将是一个不错的解决方案,因为在对源进行排序后,我希望将最便宜的作为计算属性。例如。在sources =&gt; 函数中,我可以只返回sources.firstObject、sources.get('firstObject')、sources[0] 或任何正确的语法。
      • 您可以在模型中定义它,默认为priceSources: DS.hasMany('price-source',{async:true})。如果 async 属性为 true 那么它返回 Promise 所以 then 是一个东西,如果它是 false 它返回 DS.ManyArray 所以 then 不是一个东西所以你会得到那个错误。我还没有想出任何例子,我只是通过这个ember igniter article for loading@VilleLehtinen
      猜你喜欢
      • 2019-10-17
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2015-04-16
      相关资源
      最近更新 更多