Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 返回Ember中模型属性的承诺_Javascript_Ember.js_Ember Data_Promise - Fatal编程技术网

Javascript 返回Ember中模型属性的承诺

Javascript 返回Ember中模型属性的承诺,javascript,ember.js,ember-data,promise,Javascript,Ember.js,Ember Data,Promise,我正在做一件事。它是用余烬写成的,由CouchDB支持 在主屏幕上,我想显示一个习惯列表,以及每次记录事件的最后时间。以下是我的模型的外观: App.Habit = DS.Model.extend( { type: DS.attr('string', { defaultValue: 'habit' } ), name: DS.attr( 'string' ), color: DS.attr( 'string' ), events: DS.hasMany( 'event', { a

我正在做一件事。它是用余烬写成的,由CouchDB支持

在主屏幕上,我想显示一个习惯列表,以及每次记录事件的最后时间。以下是我的模型的外观:

App.Habit = DS.Model.extend( {
  type: DS.attr('string', { defaultValue: 'habit' } ),
  name: DS.attr( 'string' ),
  color: DS.attr( 'string' ),
  events: DS.hasMany( 'event', { async: true, defaultValue: [] } ),
  style: function() {
    return 'background-color: %@'.fmt( this.get( 'color' ) )
  }.property( 'color' ),
  lastTime: function() {
    return this
      .get( 'events' )
      .then( function( events ) {
        var times = events.map( function( e ) {
          return e.get( 'time' )
        } )
        return times.length == 0 ? undefined : times.sort()[0]
      } )
  }.property( 'events' ),
} )

App.Event = DS.Model.extend( {
  type: DS.attr('string', { defaultValue: 'event' } ),
  time: DS.attr( 'date' ),
  habit: DS.belongsTo( 'habit' )
} )
请注意,
习惯
lastTime
属性返回一个承诺。当我在没有承诺的情况下执行此操作时,数组的长度为0。我的把手模板看起来像:

<script type="text/x-handlebars" id="habits">
  <div id="habits">                                                                                                                                                                                        
    {{#each}}                                                                                                                                                                                              
      <div class="row" {{action 'createEvent' id}}>
        <div class="col-xs-1 color" {{bind-attr style=style}}></div>
        <div class="col-xs-8">{{name}}</div>
        <div class="col-xs-3" data-role="timer">{{format-time-numeric lastTime}}</div>
      </div>                                                                                                                                                                                               
    {{/each}}                                                                                                                                                                                              
  </div>
</script>

时间
传递到瞬间是一种承诺,并呈现为一堆
NaN
s。如果我从
格式时间
返回一个承诺,它将呈现为
[object]
我不是余烬数据专家,但尝试在事件中使用async:false。


您还可以放入调试器:

不要从调试器返回承诺

lastTime
相反,将其写为:

lastTime: function() {
    var times =  this.get('events').map(function(event) {
                      return event.get('time');
                  });      
    return times.length == 0 ? undefined : times.sort()[0]
  } )
}.observes('events').property(),

对于这种情况,您可以使用
reduceComputed
属性:

  maxTime: Ember.reduceComputed('events.@each.time', {
    initialValue: -Infinity,
    addedItem: function(accValue, event) { 
      return Math.max(accValue, event.get('time'));
    },
    removedItem: function(accValue, event) { 
      if (event.get('time') < accValue ) {
        return accValue;
      }
    }
  })
maxTime:Ember.reduceComputed('events.@each.time'{
初始值:-无穷大,
addedItem:函数(accValue,事件){
返回Math.max(accValue,event.get('time');
},
removedItem:函数(accValue,事件){
if(event.get('time')
您的模型逻辑有缺陷。它观察“事件”的变化,但也通过承诺获得“事件”。如果“事件”已经解决,则您不需要承诺。如果“事件”尚未发生,则您无法观察它

模型通常不是承诺的场所-您的视图不理解如何显示承诺。承诺通常在路由中解决,结果存储在模型中。我会重新构建以将其移动到路线,或者如果这不可能,则让一些操作或观察者在模型中设置属性

选项1:如果事件已在内存中:

见赫里希的答案

选项2:如果事件不在内存中并且需要承诺:

类似的方法可能会奏效:

lastTime: null,
然后在控制器中执行类似于此的操作(或使用其他方式触发类似代码):


引用你的评论:

我认为Ember应该等待承诺完成并将结果发送到模板

那就是。。。一个棘手的问题。简单地说,不,它不会等待。我唯一能想到的id等待的时间是在模型钩子中。如果您从
beforeModel
model
afterModel
返回承诺,路由器将在继续之前暂停。但是,这不适用于控制器或模板,也不适用于获取模型异步关系时的情况

因此,一个可能的解决方案是暂停路由器,直到加载
事件
关系。在您的路由器中有类似的内容:

model: function(params) {
    return this.store.find('habit', params.habit_id).then(function(habit) {
        // Return another promise, to continue pausing the router
        return habit.get('lastTime');
    });
}
这将暂停路由器(并且不会呈现模板),直到您的
lastTime
属性完全计算完毕

另一个选项(我建议)是将
lastTime
属性异步插入模板中。如果更改属性的计算方式,则可以在获取
事件时更新模板:

lastTime: function() {
    var events = this.get('events');

    if (events.length <= 0) {
        return 0; // Or some other default
    }

    return events.mapBy('time').sort()[0];
}.property('events.@each.time')
lastTime:function(){
var events=this.get('events');

如果(events.length当我将
async
更改为
false
时,我得到一个错误:
TypeError:无法读取未定义的
的属性'resolve'。internet建议这可能是因为我的数据模型已损坏,但它似乎已签出。抱歉,我很难理解您的问题。您到底遇到了什么问题试图解决吗?我有一个依赖属性,
lastTime
,它是从数组中计算出来的,
events
。我正在使用CouchDB和
this.get('events')
返回承诺。我需要搜索返回的数组并在模板中显示值。如果我通过
搜索承诺的
方法并返回结果承诺,则该承诺(而不是派生值)将传递给显示模板。如果我调用
this.get('events').map
结果长度为0。我认为Ember应该等待承诺完成并将结果发送到模板。
model: function(params) {
    return this.store.find('habit', params.habit_id).then(function(habit) {
        // Return another promise, to continue pausing the router
        return habit.get('lastTime');
    });
}
lastTime: function() {
    var events = this.get('events');

    if (events.length <= 0) {
        return 0; // Or some other default
    }

    return events.mapBy('time').sort()[0];
}.property('events.@each.time')