Skip to content
This repository was archived by the owner on Sep 8, 2020. It is now read-only.

Commit eef6f9a

Browse files
committed
feat(calendar.js): wrapping any config function with $apply
Signed-off-by: Josh Kurz <josh.kurz@turner.com>
1 parent 5ee2679 commit eef6f9a

File tree

4 files changed

+152
-172
lines changed

4 files changed

+152
-172
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ The ui-calendar directive plays nicely with ng-model.
7979
An Event Sources objects needs to be created to pass into ng-model. This object will be watched for changes and update the calendar accordingly, giving the calendar some Angular Magic.
8080

8181
The ui-calendar directive expects the eventSources object to be any type allowed in the documentation for the fullcalendar. [docs](http://arshaw.com/fullcalendar/docs/event_data/Event_Source_Object/)
82-
Note that all calendar options are passed directly into `fullCalendar`, so you will need to wrap listeners to fullCalendar events in `scope.$apply`, as in example above.
82+
Note that all calendar options which are functions that are passed into the calendar are wrapped in an apply automatically.
8383

8484
## Accessing the calendar object
8585

demo/calendarDemo.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ function CalendarCtrl($scope) {
4444
]
4545
};
4646
/* alert on eventClick */
47-
$scope.alertEventOnClick = function( date, allDay, jsEvent, view ){
48-
$scope.alertMessage = ('Day Clicked ' + date);
47+
$scope.alertOnEventClick = function( event, allDay, jsEvent, view ){
48+
$scope.alertMessage = (event.title + ' was clicked ');
4949
};
5050
/* alert on Drop */
5151
$scope.alertOnDrop = function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view){
@@ -99,7 +99,7 @@ function CalendarCtrl($scope) {
9999
center: '',
100100
right: 'today prev,next'
101101
},
102-
dayClick: $scope.alertEventOnClick,
102+
eventClick: $scope.alertOnEventClick,
103103
eventDrop: $scope.alertOnDrop,
104104
eventResize: $scope.alertOnResize
105105
}

src/calendar.js

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,6 @@ angular.module('ui.calendar', [])
3333
}
3434

3535
return wrapper;
36-
},
37-
38-
addRefetchEventsCommand = function (settings, calendar) {
39-
if (!settings) {
40-
return;
41-
}
42-
43-
settings.refetchEvents = function () {
44-
calendar.fullCalendar('refetchEvents');
45-
};
4636
};
4737

4838
this.eventsFingerprint = function(e) {
@@ -160,20 +150,17 @@ angular.module('ui.calendar', [])
160150
};
161151
};
162152

163-
this.addCommands = function (settings, calendar) {
164-
addRefetchEventsCommand(settings, calendar);
165-
};
166-
167153
this.getFullCalendarConfig = function(calendarSettings, uiCalendarConfig){
168154
var config = {};
169155

170156
angular.extend(config, uiCalendarConfig);
171157
angular.extend(config, calendarSettings);
172-
173-
config.dayClick = wrapFunctionWithScopeApply(config.dayClick);
174-
config.eventClick = wrapFunctionWithScopeApply(config.eventClick);
175-
config.eventDrop = wrapFunctionWithScopeApply(config.eventDrop);
176-
config.eventResize = wrapFunctionWithScopeApply(config.eventResize);
158+
159+
angular.forEach(config, function(value,key){
160+
if (typeof value === 'function'){
161+
config[key] = wrapFunctionWithScopeApply(config[key]);
162+
}
163+
});
177164

178165
return config;
179166
};
@@ -213,8 +200,6 @@ angular.module('ui.calendar', [])
213200
var calendarSettings = attrs.uiCalendar ? scope.$parent.$eval(attrs.uiCalendar) : {},
214201
fullCalendarConfig;
215202

216-
controller.addCommands(calendarSettings, scope.calendar);
217-
218203
fullCalendarConfig = controller.getFullCalendarConfig(calendarSettings, uiCalendarConfig);
219204

220205
options = { eventSources: sources };

test/calendar.spec.js

Lines changed: 142 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -17,70 +17,66 @@ describe('uiCalendar', function () {
1717
$locale = _$locale_;
1818
$controller = _$controller_;
1919

20-
// create an array of events, to pass into the directive.
21-
scope.events = [
22-
{title: 'All Day Event',start: new Date(y, m, 1),url: 'http://www.angularjs.org'},
23-
{title: 'Long Event',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
24-
{id: 999,title: 'Repeating Event',start: new Date(y, m, d - 3, 16, 0),allDay: false},
25-
{id: 999,title: 'Repeating Event',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
26-
27-
// create an array of events, to pass into the directive.
28-
scope.events2 = [
29-
{title: 'All Day Event 2',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
30-
{title: 'Long Event 2',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
31-
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d - 3, 16, 0),allDay: false},
32-
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
33-
//array to test equals occurance
34-
scope.events3 = [
35-
{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
36-
{title: 'Long Event 3',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
37-
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d - 3, 16, 0),allDay: false},
38-
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
39-
40-
scope.calEventsExt = {
41-
color: '#f00',
42-
textColor: 'yellow',
43-
events: [
44-
{type:'party',title: 'Lunch',start: new Date(y, m, d, 12, 0),end: new Date(y, m, d, 14, 0),allDay: false},
45-
{type:'party',title: 'Lunch 2',start: new Date(y, m, d, 12, 0),end: new Date(y, m, d, 14, 0),allDay: false},
46-
{type:'party',title: 'Click for Google',start: new Date(y, m, 28),end: new Date(y, m, 29),url: 'http://google.com/'}
47-
]
48-
};
49-
50-
// create an array of events, to pass into the directive.
51-
scope.events4 = [{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.yoyoyo.com'}];
52-
53-
//event Sources array
54-
scope.eventSources = [scope.events,scope.events2]; //End of Events Array
55-
56-
scope.addSource = function(source) {
57-
scope.eventSources.push(source);
58-
};
59-
60-
scope.addChild = function(array) {
61-
array.push({
62-
title: 'Click for Google ' + scope.events.length,
63-
start: new Date(y, m, 28),
64-
end: new Date(y, m, 29),
65-
url: 'http://google.com/'
66-
});
67-
};
68-
69-
scope.remove = function(array,index) {
70-
array.splice(index,1);
71-
};
72-
73-
scope.uiConfig = {
74-
calendar:{
75-
height: 200,
76-
weekends: false,
77-
defaultView: 'month',
78-
dayClick: function(){},
79-
eventClick: function(){},
80-
eventDrop: function(){},
81-
eventResize: function(){}
82-
}
83-
};
20+
// create an array of events, to pass into the directive.
21+
scope.events = [
22+
{title: 'All Day Event',start: new Date(y, m, 1),url: 'http://www.angularjs.org'},
23+
{title: 'Long Event',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
24+
{id: 999,title: 'Repeating Event',start: new Date(y, m, d - 3, 16, 0),allDay: false},
25+
{id: 999,title: 'Repeating Event',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
26+
27+
// create an array of events, to pass into the directive.
28+
scope.events2 = [
29+
{title: 'All Day Event 2',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
30+
{title: 'Long Event 2',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
31+
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d - 3, 16, 0),allDay: false},
32+
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
33+
//array to test equals occurance
34+
scope.events3 = [
35+
{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
36+
{title: 'Long Event 3',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
37+
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d - 3, 16, 0),allDay: false},
38+
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
39+
40+
scope.calEventsExt = {
41+
color: '#f00',
42+
textColor: 'yellow',
43+
events: [
44+
{type:'party',title: 'Lunch',start: new Date(y, m, d, 12, 0),end: new Date(y, m, d, 14, 0),allDay: false},
45+
{type:'party',title: 'Lunch 2',start: new Date(y, m, d, 12, 0),end: new Date(y, m, d, 14, 0),allDay: false},
46+
{type:'party',title: 'Click for Google',start: new Date(y, m, 28),end: new Date(y, m, 29),url: 'http://google.com/'}
47+
]
48+
};
49+
50+
// create an array of events, to pass into the directive.
51+
scope.events4 = [{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.yoyoyo.com'}];
52+
53+
//event Sources array
54+
scope.eventSources = [scope.events,scope.events2]; //End of Events Array
55+
56+
scope.addSource = function(source) {
57+
scope.eventSources.push(source);
58+
};
59+
60+
scope.addChild = function(array) {
61+
array.push({
62+
title: 'Click for Google ' + scope.events.length,
63+
start: new Date(y, m, 28),
64+
end: new Date(y, m, 29),
65+
url: 'http://google.com/'
66+
});
67+
};
68+
69+
scope.remove = function(array,index) {
70+
array.splice(index,1);
71+
};
72+
73+
scope.uiConfig = {
74+
calendar:{
75+
height: 200,
76+
weekends: false,
77+
defaultView: 'month'
78+
}
79+
};
8480

8581
}));
8682

@@ -186,7 +182,7 @@ describe('uiCalendar', function () {
186182

187183
});
188184

189-
describe('calendarCtrl', function(){
185+
describe('calendarCtrl changeWatcher functionality', function(){
190186

191187
var calendar,
192188
calendarCtrl,
@@ -294,88 +290,6 @@ describe('uiCalendar', function () {
294290
scope.$apply();
295291
expect(sourcesChanged).toBe('removed');
296292
});
297-
298-
it('makes sure that dayClick is called in angular context', inject(function($timeout, $rootScope){
299-
spyOn(scope.uiConfig.calendar, 'dayClick');
300-
spyOn($rootScope,'$apply');
301-
302-
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
303-
304-
fullCalendarConfig.dayClick();
305-
306-
$timeout.flush();
307-
308-
expect($rootScope.$apply).toHaveBeenCalled();
309-
expect(scope.uiConfig.calendar.dayClick).toHaveBeenCalled();
310-
}));
311-
312-
it('makes sure that eventClick is called in angular context', inject(function($timeout, $rootScope){
313-
spyOn(scope.uiConfig.calendar, 'eventClick');
314-
spyOn($rootScope,'$apply');
315-
316-
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
317-
318-
fullCalendarConfig.eventClick();
319-
320-
$timeout.flush();
321-
322-
expect($rootScope.$apply).toHaveBeenCalled();
323-
expect(scope.uiConfig.calendar.eventClick).toHaveBeenCalled();
324-
}));
325-
326-
it('makes sure that eventDrop is called in angular context', inject(function($timeout, $rootScope){
327-
spyOn(scope.uiConfig.calendar, 'eventDrop');
328-
spyOn($rootScope,'$apply');
329-
330-
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
331-
332-
fullCalendarConfig.eventDrop();
333-
334-
$timeout.flush();
335-
336-
expect($rootScope.$apply).toHaveBeenCalled();
337-
expect(scope.uiConfig.calendar.eventDrop).toHaveBeenCalled();
338-
}));
339-
340-
it('makes sure that eventResize is called in angular context', inject(function($timeout, $rootScope){
341-
spyOn(scope.uiConfig.calendar, 'eventResize');
342-
spyOn($rootScope,'$apply');
343-
344-
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
345-
346-
fullCalendarConfig.eventResize();
347-
348-
$timeout.flush();
349-
350-
expect($rootScope.$apply).toHaveBeenCalled();
351-
expect(scope.uiConfig.calendar.eventResize).toHaveBeenCalled();
352-
}));
353-
354-
it('should not fail when addCommands is called with undefined settings ', function(){
355-
expect(calendarCtrl.addCommands).not.toThrow();
356-
});
357-
358-
it('makes sure that refetchEvents command is added on the configuration', function(){
359-
calendarCtrl.addCommands(scope.uiConfig.calendar, undefined);
360-
361-
expect(scope.uiConfig.calendar.refetchEvents).toBeDefined();
362-
});
363-
364-
it('makes sure that fullCallendar is called with \'refetchEvents\' when refetchEvents command is called', function(){
365-
var fakeCalendar ={
366-
fullCalendar: function(string){
367-
368-
}
369-
};
370-
371-
spyOn(fakeCalendar, 'fullCalendar');
372-
373-
calendarCtrl.addCommands(scope.uiConfig.calendar, fakeCalendar);
374-
375-
scope.uiConfig.calendar.refetchEvents();
376-
377-
expect(fakeCalendar.fullCalendar).toHaveBeenCalledWith('refetchEvents');
378-
});
379293
});
380294

381295
describe('Testing the ability to add calendars to the scope', function(){
@@ -427,4 +341,85 @@ describe('uiCalendar', function () {
427341
});
428342
});
429343

344+
describe('Describing calendarCtrl and its configurations functions', function(){
345+
346+
var calendarCtrl;
347+
348+
beforeEach(function(){
349+
calendarCtrl = $controller('uiCalendarCtrl', {$scope: scope, $element: null});
350+
scope.$apply();
351+
});
352+
353+
it('makes sure that all config functions are called in an angular context', inject(function($timeout, $rootScope){
354+
var functionCount = 0;
355+
scope.uiConfig = {
356+
calendar:{
357+
height: 200,
358+
weekends: false,
359+
defaultView: 'month',
360+
dayClick: function(){},
361+
eventClick: function(){},
362+
eventDrop: function(){},
363+
eventResize: function(){},
364+
eventMouseover: function(){}
365+
}
366+
};
367+
368+
spyOn($rootScope,'$apply');
369+
370+
angular.forEach(scope.uiConfig.calendar, function(value,key){
371+
if (typeof value === 'function'){
372+
functionCount++;
373+
spyOn(scope.uiConfig.calendar, key);
374+
375+
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
376+
377+
fullCalendarConfig[key]();
378+
379+
$timeout.flush();
380+
381+
expect($rootScope.$apply.callCount).toBe(functionCount);
382+
expect(scope.uiConfig.calendar[key]).toHaveBeenCalled();
383+
$rootScope.$apply.isSpy = false;
384+
}
385+
});
386+
}));
387+
388+
it('makes sure that any function that already has an apply in it does not break the calendar (backwards compatible)', inject(function($timeout, $rootScope){
389+
390+
var functionCount = 0;
391+
scope.uiConfig = {
392+
calendar:{
393+
height: 200,
394+
weekends: false,
395+
defaultView: 'month',
396+
dayClick: function(){scope.$apply();},
397+
eventClick: function(){scope.$apply();},
398+
eventDrop: function(){scope.$apply();},
399+
eventResize: function(){scope.$apply();},
400+
eventMouseover: function(){scope.$apply();}
401+
}
402+
};
403+
404+
spyOn($rootScope,'$apply');
405+
406+
angular.forEach(scope.uiConfig.calendar, function(value,key){
407+
if (typeof value === 'function'){
408+
functionCount++;
409+
spyOn(scope.uiConfig.calendar, key);
410+
411+
var fullCalendarConfig = calendarCtrl.getFullCalendarConfig(scope.uiConfig.calendar, {});
412+
413+
fullCalendarConfig[key]();
414+
415+
scope.$apply();
416+
$timeout.flush();
417+
418+
expect($rootScope.$apply.callCount).toBe(functionCount*2);
419+
expect(scope.uiConfig.calendar[key]).toHaveBeenCalled();
420+
}
421+
});
422+
}));
423+
});
424+
430425
});

0 commit comments

Comments
 (0)