承诺导致Ember Data计算属性

时间:2016-04-29 19:11:52

标签: ember.js ember-data

我试图调用外部API并将结果用作我的Ember Data模型中的计算属性。结果很好,但计算属性在Promise结算之前返回,导致未定义。这是观察者的用例吗?

export default DS.Model.extend({
  lat: DS.attr(),
  lng: DS.attr(),
  address: Ember.computed('lat', 'lng', function() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    var addr;

    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
        Ember.$.ajax(url, {                                                        
          success: function(response) {                                            
            resolve(response);                                                     
          },                                                                       
          error: function(reason) {                                                
            reject(reason);                                                        
          }                                                                        
        });                                                                        
     });                                                                          

     request.then(function(response) {                      
       addr = response.results[0].formatted_address;                              
     }, function(error) {                                                         
       console.log(error);
     })  

     return addr;
  })
});

4 个答案:

答案 0 :(得分:4)

使用DS.PromiseObject。我一直使用以下技术:

import DS from 'ember-data';

export default DS.Model.extend({

  ...

  address: Ember.computed('lat', 'lng', function() {
    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
      ...
    });                                                                          

    return DS.PromiseObject.create({ promise: request });
  }),

});

将模板中已解析的值用作{{address.content}},这将在代理的Promise结算时自动更新。

如果您想在此处执行更多操作,我建议您查看社区中其他人正在做的事情:https://emberobserver.com/?query=promise

构建一个接受DS.PromiseObject并在Promise仍处于未决状态时显示加载微调器的简单Component并不难,然后一旦显示实际值(或产生一个块)承诺解决。

我在应用程序中有一个Ember.Service,它几​​乎完全由Computed Properties组成,返回包含在DS.PromiseObjects中的Promises。它的工作效果令人惊讶。

答案 1 :(得分:1)

我在大型Ember应用程序中使用了self.set('computed_property', value);技术大约三个月,我可以告诉你它有一个非常大的问题:计算属性只能一次

当您set计算的属性值时,生成结果的函数会丢失,因此当您的相关模型属性更改时,计算属性将不会刷新。

在Ember的计算属性中使用promises是一件麻烦事,我找到的最好的技术是:

prop: Ember.computed('related', {
    // `get` receives `key` as a parameter but I never use it.
    get() {
        var self = this;
        // We don't want to return old values.
        this.set('prop', undefined);
            promise.then(function (value) {
                // This will raise the `set` method.
                self.set('prop', value);
            });
        // We're returning `prop_data`, not just `prop`.
        return this.get('prop_data');
    },
    set(key, value) {
        this.set('prop_data', value);
        return value;
    }
}),

优点:

  • 它适用于模板,因此您可以在模板中执行{{object.prop}},它将正确解析。
  • 相关属性更改时会更新。

缺点:

  • 当您使用Javascript object.get('prop');并且承诺正在解析时,它会立即返回undefined,但是如果您正在观察计算属性,则当promise解析时,观察者将再次触发最终值已设定。

也许你想知道为什么我没有在get中回复承诺;如果你这样做并在模板中使用它,它将呈现一个对象字符串表示([object Object]或类似的东西)。

我想在一个适当的计算属性实现中工作,该实现在模板中运行良好,在Javascript中返回一个promise并自动更新,可能使用DS.PromiseObjectEmber.PromiseProxyMixin,但不幸的是我没有'找时间。

如果大骗局对您的用例不是问题,请使用“获取/设置”技术,如果不尝试实施更好的方法,但严重不要只使用 {{1}它会长期给你带来很多问题,不值得。

PS。:对于这个问题,真正的最终解决方案是:如果可以避免,则永远不要在计算属性中使用promises。

PS。:顺便说一句,这种技术不是我的,而是我的前同事@ reset-reboot。

答案 2 :(得分:0)

创建一个组件(address-display.js):

import Ember from 'ember';

export default Ember.Component.extend({
  init() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    Ember.$.ajax(url, {
      success: function(response) {
        this.set('value', response.results[0].formatted_address);
      },
      error: function(reason) {
        console.log(reason);
      }
    });
  }
});

模板(components / address-display.hbs):

{{value}}

然后使用模板中的组件:

{{address-display lat=model.lat lng=model.lng}}

答案 3 :(得分:-1)

以下工作原理是解析属性并设置结果。

在这里解释: http://discuss.emberjs.com/t/promises-and-computed-properties/3333/10

export default DS.Model.extend({
  lat: DS.attr(),
  lng: DS.attr(),
  address: Ember.computed('lat', 'lng', function() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    var self = this;

    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
        Ember.$.ajax(url, {                                                        
          success: function(response) {                                            
            resolve(response);                                                     
          },                                                                       
          error: function(reason) {                                                
            reject(reason);                                                        
          }                                                                        
        });                                                                        
     }).then(function(response) {
         self.set('address', response.results[0].formatted_address);
     })
  })
});