From cc10fa94304ac8bc6a206049b03e7f010c0d0883 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Tue, 2 Jun 2015 14:30:03 -0700 Subject: [PATCH] feat(datepicker): binding for the date-picker --- src/components/calendar/datePicker.js | 66 +++++++++++++++---- src/components/calendar/dateUtil.js | 12 +++- .../calendar/demoDatePicker/style.css | 3 + 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/components/calendar/datePicker.js b/src/components/calendar/datePicker.js index 0e0b34f9446..184866389b8 100644 --- a/src/components/calendar/datePicker.js +++ b/src/components/calendar/datePicker.js @@ -1,35 +1,56 @@ (function() { 'use strict'; + // TODO(jelbourn): md-calendar shown in floating panel. + // TODO(jelbourn): little calendar icon next to input + // TODO(jelbourn): only one open md-calendar panel at a time per application + + angular.module('material.components.calendar') .directive('mdDatePicker', datePickerDirective); function datePickerDirective() { return { template: - '
' + - '
' + - '' + + '
' + + '
' + + '' + '
', require: ['ngModel', 'mdDatePicker'], scope: {}, controller: DatePickerCtrl, - controllerAs: 'ctrl' + controllerAs: 'ctrl', + link: function(scope, element, attr, controllers) { + var ngModelCtrl = controllers[0]; + var mdDatePickerCtrl = controllers[1]; + mdDatePickerCtrl.configureNgModel(ngModelCtrl); + } }; } - function DatePickerCtrl($$mdDateLocale) { + function DatePickerCtrl($scope, $element, $$mdDateLocale, $$mdDateUtil) { /** @final */ this.dateLocale = $$mdDateLocale; + /** @final */ + this.dateUtil = $$mdDateUtil; + /** @type {!angular.NgModelController} */ this.ngModelCtrl = null; - /** @type {string} */ - this.textValue = ''; + /** @type {HTMLInputElement} */ + this.inputElement = $element[0].querySelector('input'); /** @type {Date} */ - this.dateValue = null; + this.date = null; + + /** @final {!angular.JQLite} */ + this.$element = $element; + + /** @final {!angular.Scope} */ + this.$scope = $scope; + + this.attachChangeListeners(); } /** @@ -41,8 +62,31 @@ var self = this; ngModelCtrl.$render = function() { - self.dateValue = self.ngModelCtrl.$viewValue - self.textValue = self.dateLocale.format(self.ngModelCtrl.$viewValue); + self.date = self.ngModelCtrl.$viewValue; + self.inputElement.value = self.dateLocale.formatDate(self.date); }; - } + }; + + /** + * Attach event listeners for both the text input and the md-calendar. + * Events are used instead of ng-model so that updates don't infinitely update the other + * on a change. This should also be more performant than using a $watch. + */ + DatePickerCtrl.prototype.attachChangeListeners = function() { + var self = this; + + self.$scope.$on('md-calendar-change', function(event, date) { + self.ngModelCtrl.$setViewValue(date); + self.inputElement.value = self.dateLocale.formatDate(date); + }); + + // TODO(jelbourn): debounce + self.inputElement.addEventListener('input', function() { + var parsedDate = self.dateLocale.parseDate(self.inputElement.value); + if (self.dateUtil.isValidDate(parsedDate)) { + self.date = parsedDate; + self.$scope.$apply(); + } + }); + }; })(); diff --git a/src/components/calendar/dateUtil.js b/src/components/calendar/dateUtil.js index a161bd772fd..53a2c6ac978 100644 --- a/src/components/calendar/dateUtil.js +++ b/src/components/calendar/dateUtil.js @@ -19,7 +19,8 @@ incrementDays: incrementDays, incrementMonths: incrementMonths, getLastDateOfMonth: getLastDateOfMonth, - isSameDay: isSameDay + isSameDay: isSameDay, + isValidDate: isValidDate }; /** @@ -162,5 +163,14 @@ function getLastDateOfMonth(date) { return new Date(date.getFullYear(), date.getMonth(), getNumberOfDaysInMonth(date)); } + + /** + * Checks whether a date is valid. + * @param {Date} date + * @return {boolean} Whether the date is a valid Date. + */ + function isValidDate(date) { + return date != null && date.getTime && !isNaN(date.getTime()); + } }); })(); diff --git a/src/components/calendar/demoDatePicker/style.css b/src/components/calendar/demoDatePicker/style.css index 1156334a7f7..8a4690861dd 100644 --- a/src/components/calendar/demoDatePicker/style.css +++ b/src/components/calendar/demoDatePicker/style.css @@ -1 +1,4 @@ /** Demo styles for mdCalendar. */ +.md-date-picker { + border: 2px solid darkred; +}