Skip to content

Instantly share code, notes, and snippets.

@csaftoiu
Created November 9, 2015 21:50
Show Gist options
  • Save csaftoiu/0c930dd0edb11a71d7fc to your computer and use it in GitHub Desktop.
Save csaftoiu/0c930dd0edb11a71d7fc to your computer and use it in GitHub Desktop.
Angular binding for Foundation Datepicker
'use strict';
/**
* @ngdoc overview
* @name foundation.datepicker.angular
* @description
* # foundation.datepicker.angular
*
* Add angular support for {@link http://foundation-datepicker.peterbeno.com/example.html foundation-datepicker}.
*/
angular
.module('foundation.datepicker.angular', [])
/**
* @ngdoc directive
* @name foundation.datepicker.angular.directive:datePicker
*
* @restrict E
*
* @description Element directive for
* {@link http://foundation-datepicker.peterbeno.com/example.html foundation-datepicker}.
* Adds a text input field which, when clicked, pops up the datepicker.
*
* @param {string} ngModel Assignable angular expression to data-bind the date to.
* This should be a JavaScript Date object.
* @param {string=} format The date format, combination of d, dd, m, mm, yy, yyyy, hh, ii. Default `"yyyy-mm-dd"`.
* @param {string=} language Two-char iso shortcut of language you want to use, default `"en"`. Must include the
* proper locale `.js` file, via a `<script>` tag.
* @param {string=} pickTime Provide this param to enable picking the time after picking the date.
* @param {expression=} ngMindate Specify a minimum allowable date.
* @param {expression=} ngMaxdate Specify a maximum allowable date.
*
* @example
* Generate an input element which picks a date and time, bound to `$scope.travelTime`, that must be >= today's date.
*
* HTML:
* <pre>
* <date-picker ng-model="travelTime" pick-time
* format="yyyy-mm-dd hh:ii"
* ng-mindate="today"></date-picker>
* </pre>
* Controller:
* <pre>
* $scope.travelTime = new Date();
* var now = new Date();
* $scope.today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
* </pre>
* Output may be something like: <br>
* <img src="http://i.imgur.com/5KWGtqu.png">
*/
.directive('datePicker', function () {
var toFakeUTC = function (realLocal) {
return new Date(Date.UTC(
realLocal.getFullYear(), realLocal.getMonth(), realLocal.getDate(),
realLocal.getHours(), realLocal.getMinutes(), realLocal.getSeconds()));
};
var fromFakeUTC = function (fakeUTC) {
return new Date(fakeUTC.getTime() + (fakeUTC.getTimezoneOffset() * 60000));
};
return {
require: 'ngModel',
restrict: 'E',
scope: { format: "@", language: "@", pickTime: "@",
mindate: '=ngMindate', maxdate: '=ngMaxdate'},
template: '<input type="text" ng-model="formattedDate">',
link: function (scope, element, attrs, ngModelCtrl) {
if (scope.format === undefined) {
scope.format = "yyyy-mm-dd";
}
if (scope.language === undefined) {
scope.language = "en";
}
var $input = $(element.children("input")[0]);
var datepicker = $input.fdatepicker({
format: scope.format,
language: scope.language,
pickTime: attrs.pickTime !== undefined && scope.pickTime !== "0",
onRender: function (date) {
// scope.mindate/scope.maxdate are in real local time, convert to
// fake utc to compare equally with the date picker
if (scope.mindate !== undefined) {
if (date.valueOf() < toFakeUTC(scope.mindate).valueOf()) {
return 'disabled';
}
}
if (scope.maxdate !== undefined) {
if (date.valueOf() > toFakeUTC(scope.maxdate).valueOf()) {
return 'disabled';
}
}
return '';
}
}).data('datepicker');
// modelValue is a Date object, in whatever local time zone
// viewValue is the formatted date according to foundation-datepicker
ngModelCtrl.$formatters.push(function (modelValue) {
// formatDate formats the date in UTC time, so we need to get a date which, when formatted in UTC, would
// look like this local timezone
return $.fn.fdatepicker.DPGlobal.formatDate(
toFakeUTC(modelValue), $.fn.fdatepicker.DPGlobal.parseFormat(scope.format), scope.language);
});
ngModelCtrl.$render = function () {
// set view value
scope.formattedDate = ngModelCtrl.$viewValue;
// lock to model value. not sure why this is needed but without it the values
// sometimes get out of sync
if (datepicker.getDate() !== ngModelCtrl.$modelValue) {
datepicker.update(ngModelCtrl.$modelValue);
}
};
// updated by the datepicker acting on the <input> field
scope.$watch('formattedDate', function (newValue, oldValue) {
ngModelCtrl.$setViewValue(newValue);
});
ngModelCtrl.$parsers.push(function (viewValue) {
var fakeUTC = $.fn.fdatepicker.DPGlobal.parseDate(
viewValue, $.fn.fdatepicker.DPGlobal.parseFormat(scope.format), scope.language);
// asUTC is 'fake' UTC (as a UTC date, but in the local timezone)
// convert it to real UTC
return fromFakeUTC(fakeUTC);
});
// watch mindate/maxdate changes, set value if it's over/under
scope.$watch('mindate', function (newMin) {
if (newMin === undefined) {
return;
}
if (datepicker.getDate() < newMin) { // handles UTC conversions
datepicker.update(newMin);
}
});
scope.$watch('maxdate', function (newMax) {
if (newMax === undefined) {
return;
}
if (datepicker.getDate() > newMax) {
datepicker.update(newMax);
}
});
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment