It’s all about time. SEP, like most organizations, lives and dies by time sheets. Our time sheets are two weeks long. Each entry has a start time, a project code, a description, and a duration. Easy enough, but what does that have to do with EmberJS?
To Quote Miss Jackson, “I Want to be the One in Control”.
Each timesheet is an array of such entries. If we use an array controller to wrap the array model, we can leverage a lot of assumptions about controlling a number of items.
OK, Computed Properties
Controllers can compute properties, such as the total duration of time logged on a time sheet. In addition, we can validate the timesheet, checking for overlaps and showing the billable time.
App.EntryCollectionController = Ember.ArrayController.extend({ totalDuration: function(){ return this.reduce(function(sum,entry){ return entry.duration + sum; }, 0); }.property('@each.duration'), isValid: function(){ var otherEntries = this.get('[]'); this.reduce(function(isValid, entry, index){ // TODO: the impl of doesntOverlapAfter is left as an exercise to the reader return isValid && doesntOverlapAfter(entry, otherEntries, index); }) }.property('@each.startTime', '@each.duration') });
And we can specify the name of the controller used to wrap each element in the model’s array. In our case, we will use it to calculate the end time from the duration.
App.EntryCollectionController.reopen({ itemController: 'entry' });
Objectifying Things for Fun and Profit
Those elements are likely an object controller.
App.EntryController = Ember.ObjectController.extend({ endTime : function(){ var time = this.get('startTime').clone(); time.setMinutes(time.getMinutes() + this.get('duration') * 60); return time; }.property('startTime', 'duration') })
All Things are Related
So the collection of entries needs to relate to another controller. In our case, it is the timesheet itself.
App.EntryCollectionController.reopen({ needs: ['timesheet'] });