在我的ember应用程序中,我使用异步加载的数据(使用ember数据和rest-adapter)与把手一起显示。加载和渲染数据后,我想操纵这些数据的呈现方式(计算它们所在的位置)。这也需要在视口大小调整上完成。
目前,我正试图让这项工作采用中提出的方法 How to catch whether array was inserted in handlebar in Ember? 和 Run jquery at the end of Ember.CollectionView rendering。 我甚至尝试使用schedule而不是scheduleOnce导致只调用一次display update方法,但仍然没有呈现异步加载的数据,并且在加载和呈现数据后方法不会再次调用。
export default Ember.View.extend({
templateName: 'calendar',
didInsertElement: function() {
this._super();
this.$('#calender_button_new').click(function(){
document.location.href= "index.html#/add-appointment/select-employee";
});
this.$('#calender_button_home').click(function(){
document.location.href= "index.html#/home";
});
},
updateCalendar: function() {
console.log(this.$('.appointment').length);
var view = this;
this.$('.appointment').each(function(index, item){
var id = $(item).attr('data-appointment');
view.controller.store.find('appointment', id).then(function(appointment){
var beginning_base = Math.floor(appointment.get('beginning'));
var end_base = Math.floor(appointment.get('end'));
// get cell where appointment starts, each cell can be identified by the attributes data-time and data-employee
var beginning_block = $('td[data-employee="' + appointment.get('doneBy').get('id') + '"][data-time="' + beginning_base + '"]');
var end_block = $('td[data-employee="' + appointment.get('doneBy').get('id') + '"][data-time="' + end_base + '"]');
// calculate exact position in the cell when the appointment starts, one cell covers an hour but the appointment might not start at full hour
var beginning_offset = beginning_block.outerHeight()*(appointment.get('beginning')-beginning_base);
var end_offset = end_block.outerHeight()*(appointment.get('end')-end_base);
$(item).css({top:beginning_block.offset().top+beginning_offset-59,
left:beginning_block.offset().left,
width: beginning_block.outerWidth(),
height:end_block.offset().top-beginning_block.offset().top+end_offset,
background:'red'});
});
});
},
init: function() {
this._super();
$(window).bind('resize', $.proxy(this.updateCalendar, this));
},
willDestroy: function() {
this._super();
$(window).unbind('resize');
}
});
通过这种方法,它不应该是必须要注意实现的承诺(?)。另一方面,这是我能想到为什么这不起作用的唯一原因。 (注意:在手动调整窗口大小时,一切正常。只是初始渲染给我带来麻烦。) 我实际上要听哪个事件让它起作用?
也许我应该提到我使用ArrayController,视图是数组元素的容器。 因此结构是:
-Calendar (ArrayController, View with afterRender event)
-Day (Item of Calendar, does not have a view - uses calendar view/template to be displayed)
calendar.hbs-template的相关部分是:
{{#each}}
{{#each appointment in appointments}}
<div class="appointment" {{bind-attr data-appointment="appointment.id"}}>{{appointment.title}}</div>
{{/each}}
{{/each}}
日历模型只是请求日期(CalendarRoute的一部分)
export default Ember.Route.extend({
model: function() {
return this.store.find('Day');
},
});
日模型本身:
export default DS.Model.extend({
date: DS.attr('string'),
appointments: DS.hasMany('Appointment', {
async: true,
inverse: null
}),
employees: DS.hasMany('Employee', {
async: true,
inverse: null
}),
opening: DS.attr('number'),
closing: DS.attr('number')
});
约会模式
export default DS.Model.extend({
title: DS.attr('string'),
comment: DS.attr('string'),
doneBy: DS.belongsTo('Employee'),
beginning: DS.attr('number'),
end: DS.attr('number')
});
日模型由控制器支持,但不包含任何相关内容(仅根据日期模型中的开始和结束时间创建时间段的计算字段)。
我更新了所有源代码。如果您想知道这是怎么回事,请访问http://arshaw.com/fullcalendar/(周视图)。而不是在不同的日子里,我让员工在y轴上。计划没有拖放,因此我只使用整整几个小时(而不是30分钟)。
答案 0 :(得分:1)
<强> CalendarRoute 强>
setupController: function(controller, day) {
this._super(controller, day);
// Pre-load the comments
// The 'get' call will result in an AJAX call to get
// the comments and returns a promise
Ember.RSVP.makePromise = function(maybePromise) {
// Test if it's a promise
if (maybePromise.then) {
// Then return it
return maybePromise;
} else {
// Wrap it in a Promise that resolves directly
return Ember.RSVP.resolve(maybePromise);
}
};
var appointments = day.get('appointments');
// Wait until the promise has been resolved
appointments.then(function() {
// Wait until all templates have finished rendering
Ember.run.scheduleOnce('afterRender', this, function() {
// Here goes my jQuery code
}
}
}
答案 1 :(得分:0)
在Ember中观察数组的长度就像观察property.[]
一样简单。考虑到JS正在写DOM,你永远不应该像你想要的那样观看DOM!
我认为一个好的,Emberish方法是对arrayController中的每个项使用itemController,并将style属性绑定到div.appointment
或任何想要重新定位的元素。 style
属性本身将是基于返回数据的计算属性。这是一个简化的例子:
让我们假设元素的位置以某种方式相对于月份。
App.CalendarController = Em.ArrayController.extend({
itemController: 'day'
});
App.DayController = Em.ObjectController.extend({
positioning: function() {
var top = 'top: ' + this.get('month') / 2 + 'px;';
var left = 'left: ' + this.get('month') * 5 + 'px;';
return top + left;
}.property('month'),
});
你的模板:
{{#each controller}}
<div {{bind-attr style=positioning}}>{{title}}</div>
{{/each}}
或者,您可以将Em.ColectionView与itemViewClass一起使用。
对于窗口调整大小,利用百分比定位可能意味着您不必注意调整大小,您可以使用位置和负百分比边距相对于其宽度移动元素(即创建相对于窗口的位置移动和/或元素宽度与css)。但是,这不是JS解决方案。
相反,基于Ember的解决方案是使用以下方法触发事件,对其进行去抖(因此您不会进行过多调用)并重新计算属性 - 请注意:以下尚未适应您决定管理视图/控制器的任何方式,但理论是正确和适用的。同样,这是一个简化的例子:
App.IndexView = Em.View.extend({
positionTrigger: false,
watchForResize: function() {
$(window).bind('resize', $.proxy(this.resize, this));
}.on('didInsertElement'),
resize: function() {
// No repeat calls within 200ms
Em.run.debounce(this, this.toggleProperty, 'positionTrigger', 200);
},
positioning: function() {
// Whatever you want to do to the position here
var top = 'top: ' + this.get('month') / 2 + 'px;';
var left = 'left: ' + this.get('month') * 5 + 'px;';
return top + left; // Updates style binding in template
}.property('positionTrigger', 'month'),
});
请注意:组合上述两种方法的方式可能有所不同(例如,在集合中使用itemViewClass或在itemController中完成所有操作),但您将能够实现您想要的效果如何通过组合第一部分和第二部分的方法来实现。
根据用例的不同,您可能只想让positionTrigger
属性上的观察者执行其他操作。