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

Commit

Permalink
feat(datepicker): binding for the date-picker
Browse files Browse the repository at this point in the history
  • Loading branch information
jelbourn committed Aug 13, 2015
1 parent f3457b8 commit 8a8824a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 20 deletions.
25 changes: 17 additions & 8 deletions src/components/calendar/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
'</div>' +
'<div aria-live="polite"></div>' +
'</div>',
scope: {},
restrict: 'E',
require: ['ngModel', 'mdCalendar'],
controller: CalendarCtrl,
Expand Down Expand Up @@ -160,9 +161,8 @@
this.cellClickHandler = function() {
if (this.dataset.timestamp) {
$scope.$apply(function() {
self.ngModelCtrl.$setViewValue(new Date(Number(this.dataset.timestamp)));
self.ngModelCtrl.$render();
}.bind(this));
self.setNgModelValue(new Date(Number(this.dataset.timestamp)));
}.bind(this)); // The `this` here is the cell element.
}
};

Expand Down Expand Up @@ -195,7 +195,7 @@
CalendarCtrl.prototype.buildInitialCalendarDisplay = function() {
this.buildWeekHeader();

this.displayDate = this.selectedDate || new Date();
this.displayDate = this.selectedDate || new Date(Date.now());
var nextMonth = this.dateUtil.getDateInNextMonth(this.displayDate);
this.calendarElement.appendChild(this.buildCalendarForMonth(this.displayDate));
this.calendarElement.appendChild(this.buildCalendarForMonth(nextMonth));
Expand Down Expand Up @@ -237,8 +237,7 @@
// Handled key events fall into two categories: selection and navigation.
// Start by checking if this is a selection event.
if (event.which === self.keyCode.ENTER) {
self.ngModelCtrl.$setViewValue(self.displayDate);
self.ngModelCtrl.$render();
self.setNgModelValue(self.displayDate);
event.preventDefault();
return;
}
Expand Down Expand Up @@ -281,6 +280,16 @@
}
};

/**
*
* @param {Date} date
*/
CalendarCtrl.prototype.setNgModelValue = function(date) {
this.$scope.$emit('md-calendar-change', date);
this.ngModelCtrl.$setViewValue(date);
this.ngModelCtrl.$render();
};

/**
* Focus the cell corresponding to the given date.
* @param {Date} date
Expand Down Expand Up @@ -504,8 +513,8 @@
return this.$q.when();
}

// If trying to show a null or undefined date, do nothing.
if (!date) {
// If trying to show an invalid date, do nothing.
if (!this.dateUtil.isValidDate(date)) {
return this.$q.when();
}

Expand Down
66 changes: 55 additions & 11 deletions src/components/calendar/datePicker.js
Original file line number Diff line number Diff line change
@@ -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:
'<div>' +
'<input ng-model="textValue"> <br>' +
'<md-calendar ng-model="dateValue"></md-calendar>' +
'<div class="md-date-picker">' +
'<input> <br>' +
'<md-calendar ng-model="ctrl.date"></md-calendar>' +
'</div>',
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();
}

/**
Expand All @@ -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();
}
});
};
})();
12 changes: 11 additions & 1 deletion src/components/calendar/dateUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
incrementDays: incrementDays,
incrementMonths: incrementMonths,
getLastDateOfMonth: getLastDateOfMonth,
isSameDay: isSameDay
isSameDay: isSameDay,
isValidDate: isValidDate
};

/**
Expand Down Expand Up @@ -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());
}
});
})();
3 changes: 3 additions & 0 deletions src/components/calendar/demoDatePicker/style.css
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/** Demo styles for mdCalendar. */
.md-date-picker {
border: 2px solid darkred;
}

0 comments on commit 8a8824a

Please sign in to comment.