Ember.js Ember数据计算属性中的承诺结果

Ember.js Ember数据计算属性中的承诺结果,ember.js,ember-data,Ember.js,Ember Data,我正在尝试调用外部API,并将结果用作我的Ember数据模型中的计算属性。获取的结果很好,但计算属性在承诺解析之前返回,导致未定义。这是一个观察者的用例吗 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.ge

我正在尝试调用外部API,并将结果用作我的Ember数据模型中的计算属性。获取的结果很好,但计算属性在承诺解析之前返回,导致未定义。这是一个观察者的用例吗

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;
  })
});
创建一个组件(address display.js):

模板(组件/地址显示.hbs):

然后使用模板中的组件:

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

下面的工作原理是解析属性内部并设置结果

解释如下:


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

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

在Ember中使用computed properties中的promises是一件麻烦事,我发现的最好的技术是:

prop:Ember.computed('related'){
//'get'接收'key'作为参数,但我从不使用它。
得到(){
var self=这个;
//我们不想返回旧值。
此.set('prop',未定义);
承诺。然后(函数(值){
//这将引发“set”方法。
self.set('prop',value);
});
//我们返回的是'prop_data',而不仅仅是'prop'。
返回这个.get('prop_data');
},
设置(键、值){
此.set('prop_data',值);
返回值;
}
}),
优点:

  • 它在模板上工作,因此您可以在模板中执行
    {{object.prop}}
    ,它将正确解析
  • 它会在相关属性更改时更新
缺点:

  • 当您在Javascript
    object.get('prop')中执行此操作时值,但是如果您正在观察computed属性,当承诺解析并设置最终值时,观察者将再次激发
也许你想知道为什么我没有在
get
中返回承诺;如果您这样做并在模板中使用它,它将呈现对象字符串表示(
[object object]
或类似的内容)

我想在一个适当的计算属性实现中工作,该实现在模板中运行良好,在Javascript中返回一个承诺并自动更新,可能使用类似于或的东西,但不幸的是,我没有找到时间

如果对您的用例来说,大问题不是问题,请使用“get/set”技术,如果不尝试实现更好的方法,请认真地不要只使用
self.set('prop',value'),从长远来看,它会给你带来很多问题,这不值得

PS.:然而,这个问题真正的最终解决方案是:如果可以避免的话,永远不要在计算属性中使用承诺

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

使用。我一直在使用以下技巧:

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}
,当代理承诺解析时,该值将自动更新

如果你想在这里做更多的事情,我建议你看看社区中其他人在做什么:

构建一个简单的组件并不难,它接受一个
DS.PromiseObject
,并在承诺仍然挂起时显示一个加载微调器,然后在承诺解决后显示实际值(或生成一个块)


我的应用程序中有一个
Ember.Service
,它几乎完全由计算属性组成,这些属性返回用DS.PromiseObjects包装的承诺。它出人意料地无缝工作。

抱歉,我删除了我的答案,因为它们不起作用((更多信息请参见此)更好的方法是使用组件显示地址,给定lat和lng作为输入。它可以在其
init
方法中触发请求,并在
success
函数中设置display属性。感谢您的帮助,Steve!上面的链接提供了一个有效的答案。我更喜欢这个组件解决方案它保留了模型中包含的逻辑。很高兴您让它正常工作,很抱歉错误的开始!欢迎使用StackOverflow!感谢您的输入!我还没有遇到self.set的问题,但我会尝试一下并报告回来。我会立即返回一个值,这样我就不会有未定义的问题。这项工作非常适合通知美国呃,正在取得进展。可以报告说,这很有效,我排除了
prop_data
self.set
是这里的关键点。我不知道
PromiseObject
。我将尝试一下。为了避免手动设置计算属性值,并使用为此用途而精心编制的特定Ember类,我将使用+1E
{{address-display lat=model.lat lng=model.lng}}
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);
     })
  })
});
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 });
  }),

});