Javascript 返回Ember中模型属性的承诺
我正在做一件事。它是用余烬写成的,由CouchDB支持 在主屏幕上,我想显示一个习惯列表,以及每次记录事件的最后时间。以下是我的模型的外观: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
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')