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

Commit 8a8824a

Browse files
committed
feat(datepicker): binding for the date-picker
1 parent f3457b8 commit 8a8824a

File tree

4 files changed

+86
-20
lines changed

4 files changed

+86
-20
lines changed

src/components/calendar/calendar.js

+17-8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'</div>' +
4040
'<div aria-live="polite"></div>' +
4141
'</div>',
42+
scope: {},
4243
restrict: 'E',
4344
require: ['ngModel', 'mdCalendar'],
4445
controller: CalendarCtrl,
@@ -160,9 +161,8 @@
160161
this.cellClickHandler = function() {
161162
if (this.dataset.timestamp) {
162163
$scope.$apply(function() {
163-
self.ngModelCtrl.$setViewValue(new Date(Number(this.dataset.timestamp)));
164-
self.ngModelCtrl.$render();
165-
}.bind(this));
164+
self.setNgModelValue(new Date(Number(this.dataset.timestamp)));
165+
}.bind(this)); // The `this` here is the cell element.
166166
}
167167
};
168168

@@ -195,7 +195,7 @@
195195
CalendarCtrl.prototype.buildInitialCalendarDisplay = function() {
196196
this.buildWeekHeader();
197197

198-
this.displayDate = this.selectedDate || new Date();
198+
this.displayDate = this.selectedDate || new Date(Date.now());
199199
var nextMonth = this.dateUtil.getDateInNextMonth(this.displayDate);
200200
this.calendarElement.appendChild(this.buildCalendarForMonth(this.displayDate));
201201
this.calendarElement.appendChild(this.buildCalendarForMonth(nextMonth));
@@ -237,8 +237,7 @@
237237
// Handled key events fall into two categories: selection and navigation.
238238
// Start by checking if this is a selection event.
239239
if (event.which === self.keyCode.ENTER) {
240-
self.ngModelCtrl.$setViewValue(self.displayDate);
241-
self.ngModelCtrl.$render();
240+
self.setNgModelValue(self.displayDate);
242241
event.preventDefault();
243242
return;
244243
}
@@ -281,6 +280,16 @@
281280
}
282281
};
283282

283+
/**
284+
*
285+
* @param {Date} date
286+
*/
287+
CalendarCtrl.prototype.setNgModelValue = function(date) {
288+
this.$scope.$emit('md-calendar-change', date);
289+
this.ngModelCtrl.$setViewValue(date);
290+
this.ngModelCtrl.$render();
291+
};
292+
284293
/**
285294
* Focus the cell corresponding to the given date.
286295
* @param {Date} date
@@ -504,8 +513,8 @@
504513
return this.$q.when();
505514
}
506515

507-
// If trying to show a null or undefined date, do nothing.
508-
if (!date) {
516+
// If trying to show an invalid date, do nothing.
517+
if (!this.dateUtil.isValidDate(date)) {
509518
return this.$q.when();
510519
}
511520

src/components/calendar/datePicker.js

+55-11
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,56 @@
11
(function() {
22
'use strict';
33

4+
// TODO(jelbourn): md-calendar shown in floating panel.
5+
// TODO(jelbourn): little calendar icon next to input
6+
// TODO(jelbourn): only one open md-calendar panel at a time per application
7+
8+
49
angular.module('material.components.calendar')
510
.directive('mdDatePicker', datePickerDirective);
611

712
function datePickerDirective() {
813
return {
914
template:
10-
'<div>' +
11-
'<input ng-model="textValue"> <br>' +
12-
'<md-calendar ng-model="dateValue"></md-calendar>' +
15+
'<div class="md-date-picker">' +
16+
'<input> <br>' +
17+
'<md-calendar ng-model="ctrl.date"></md-calendar>' +
1318
'</div>',
1419
require: ['ngModel', 'mdDatePicker'],
1520
scope: {},
1621
controller: DatePickerCtrl,
17-
controllerAs: 'ctrl'
22+
controllerAs: 'ctrl',
23+
link: function(scope, element, attr, controllers) {
24+
var ngModelCtrl = controllers[0];
25+
var mdDatePickerCtrl = controllers[1];
26+
mdDatePickerCtrl.configureNgModel(ngModelCtrl);
27+
}
1828
};
1929
}
2030

21-
function DatePickerCtrl($$mdDateLocale) {
31+
function DatePickerCtrl($scope, $element, $$mdDateLocale, $$mdDateUtil) {
2232
/** @final */
2333
this.dateLocale = $$mdDateLocale;
2434

35+
/** @final */
36+
this.dateUtil = $$mdDateUtil;
37+
2538
/** @type {!angular.NgModelController} */
2639
this.ngModelCtrl = null;
2740

28-
/** @type {string} */
29-
this.textValue = '';
41+
/** @type {HTMLInputElement} */
42+
this.inputElement = $element[0].querySelector('input');
3043

3144
/** @type {Date} */
32-
this.dateValue = null;
45+
this.date = null;
46+
47+
/** @final {!angular.JQLite} */
48+
this.$element = $element;
49+
50+
/** @final {!angular.Scope} */
51+
this.$scope = $scope;
52+
53+
this.attachChangeListeners();
3354
}
3455

3556
/**
@@ -41,8 +62,31 @@
4162

4263
var self = this;
4364
ngModelCtrl.$render = function() {
44-
self.dateValue = self.ngModelCtrl.$viewValue
45-
self.textValue = self.dateLocale.format(self.ngModelCtrl.$viewValue);
65+
self.date = self.ngModelCtrl.$viewValue;
66+
self.inputElement.value = self.dateLocale.formatDate(self.date);
4667
};
47-
}
68+
};
69+
70+
/**
71+
* Attach event listeners for both the text input and the md-calendar.
72+
* Events are used instead of ng-model so that updates don't infinitely update the other
73+
* on a change. This should also be more performant than using a $watch.
74+
*/
75+
DatePickerCtrl.prototype.attachChangeListeners = function() {
76+
var self = this;
77+
78+
self.$scope.$on('md-calendar-change', function(event, date) {
79+
self.ngModelCtrl.$setViewValue(date);
80+
self.inputElement.value = self.dateLocale.formatDate(date);
81+
});
82+
83+
// TODO(jelbourn): debounce
84+
self.inputElement.addEventListener('input', function() {
85+
var parsedDate = self.dateLocale.parseDate(self.inputElement.value);
86+
if (self.dateUtil.isValidDate(parsedDate)) {
87+
self.date = parsedDate;
88+
self.$scope.$apply();
89+
}
90+
});
91+
};
4892
})();

src/components/calendar/dateUtil.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
incrementDays: incrementDays,
2020
incrementMonths: incrementMonths,
2121
getLastDateOfMonth: getLastDateOfMonth,
22-
isSameDay: isSameDay
22+
isSameDay: isSameDay,
23+
isValidDate: isValidDate
2324
};
2425

2526
/**
@@ -162,5 +163,14 @@
162163
function getLastDateOfMonth(date) {
163164
return new Date(date.getFullYear(), date.getMonth(), getNumberOfDaysInMonth(date));
164165
}
166+
167+
/**
168+
* Checks whether a date is valid.
169+
* @param {Date} date
170+
* @return {boolean} Whether the date is a valid Date.
171+
*/
172+
function isValidDate(date) {
173+
return date != null && date.getTime && !isNaN(date.getTime());
174+
}
165175
});
166176
})();
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
/** Demo styles for mdCalendar. */
2+
.md-date-picker {
3+
border: 2px solid darkred;
4+
}

0 commit comments

Comments
 (0)