Skip to content

Commit fcfaf92

Browse files
committed
feat(datepicker): timeless-json-mode
datepickerConfig option for json models when we don't care about the time. * on init and parse: sets model to 'yyyy-MM-dd' format * on format: converts model to date before normal formatting [codepen](http://codepen.io/davious/pen/gpyVQm?editors=101) Related: angular-ui#1891, angular-ui#2702, angular-ui#2906, angular-ui#2952
1 parent f8eab55 commit fcfaf92

File tree

2 files changed

+89
-2
lines changed

2 files changed

+89
-2
lines changed

Diff for: src/datepicker/datepicker.js

+38-2
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar
514514
onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus,
515515
datepickerPopupTemplateUrl = angular.isDefined(attrs.datepickerPopupTemplateUrl) ? attrs.datepickerPopupTemplateUrl : datepickerPopupConfig.datepickerPopupTemplateUrl,
516516
datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl,
517+
timelessJsonMode = angular.isDefined(attrs.timelessJsonMode) ? attrs.timelessJsonMode : datepickerPopupConfig.timelessJsonMode,
517518
cache = {};
518519

519520
scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
@@ -535,6 +536,19 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar
535536
return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
536537
};
537538

539+
scope.jsonToDate = function(date) {
540+
if (date && angular.isString(date) && date.indexOf('-') > -1) {
541+
var update = date.indexOf('T') > -1;
542+
date = date.substring(0, 10).split('-');
543+
date = new Date(+date[0], +date[1] - 1, +date[2]);
544+
if(update) {
545+
ngModel.$setViewValue(dateFilter(date, dateFormat));
546+
ngModel.$render();
547+
}
548+
}
549+
return date;
550+
};
551+
538552
var isHtml5DateInput = false;
539553
if (datepickerPopupConfig.html5Types[attrs.type]) {
540554
dateFormat = datepickerPopupConfig.html5Types[attrs.type];
@@ -649,15 +663,15 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar
649663
if (isNaN(date)) {
650664
return undefined;
651665
} else {
652-
return date;
666+
return timelessJsonMode ? dateFilter(date, 'yyyy-MM-dd') : date;
653667
}
654668
} else {
655669
return undefined;
656670
}
657671
}
658672

659673
function validator(modelValue, viewValue) {
660-
var value = modelValue || viewValue;
674+
var value = (timelessJsonMode ? scope.jsonToDate(modelValue) : modelValue) || viewValue;
661675

662676
if (!attrs.ngRequired && !value) {
663677
return true;
@@ -684,11 +698,17 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar
684698
ngModel.$validators.date = validator;
685699
ngModel.$parsers.unshift(parseDate);
686700
ngModel.$formatters.push(function(value) {
701+
if(timelessJsonMode) {
702+
value = scope.jsonToDate(value);
703+
}
687704
scope.date = value;
688705
return ngModel.$isEmpty(value) ? value : dateFilter(value, dateFormat);
689706
});
690707
} else {
691708
ngModel.$formatters.push(function(value) {
709+
if(timelessJsonMode) {
710+
value = scope.jsonToDate(value);
711+
}
692712
scope.date = value;
693713
return value;
694714
});
@@ -817,4 +837,20 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar
817837
return attrs.templateUrl || 'template/datepicker/popup.html';
818838
}
819839
};
840+
})
841+
842+
.directive('datepickerJsonUtils', function() {
843+
return {
844+
restrict: 'A',
845+
link: function(scope) {
846+
scope.jsonToTicks = function(date) {
847+
if (date && angular.isString(date) && date.indexOf('-') > -1) {
848+
date = date.substring(0, 10).split('-');
849+
date = new Date(+date[0], +date[1] - 1, +date[2]);
850+
}
851+
return date.getTime ? date.getTime() : null;
852+
};
853+
scope.oneDay = 1000 * 60 * 60 * 24;
854+
}
855+
};
820856
});

Diff for: src/datepicker/test/datepicker.spec.js

+51
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,57 @@ describe('datepicker directive', function() {
12551255

12561256
});
12571257

1258+
describe('in timelessJsonMode with an ngModelController having formatters and parsers', function() {
1259+
var inputEl, dropdownEl, $document, $sniffer, $timeout;
1260+
1261+
function assignElements(wrapElement) {
1262+
inputEl = wrapElement.find('input');
1263+
dropdownEl = wrapElement.find('ul');
1264+
element = dropdownEl.find('table');
1265+
}
1266+
1267+
beforeEach(inject(function() {
1268+
$rootScope.date = '2010-09-30T00:00:00.000';
1269+
$rootScope.isopen = true;
1270+
var wrapper = $compile('<div><input ng-model="date" datepicker-popup="MM/dd/yyyy" timeless-json-mode="true" is-open="isopen"></div>')($rootScope);
1271+
$rootScope.$digest();
1272+
assignElements(wrapper);
1273+
}));
1274+
1275+
it('formats model to yyyy-MM-dd on initialization', function() {
1276+
expect(inputEl.val()).toBe('09/30/2010');
1277+
expect($rootScope.date).toEqual('2010-09-30');
1278+
});
1279+
1280+
it('updates the input when a day is clicked', function() {
1281+
clickOption(17);
1282+
expect(inputEl.val()).toBe('09/15/2010');
1283+
expect($rootScope.date).toEqual('2010-09-15');
1284+
});
1285+
});
1286+
1287+
describe('datepickerJsonUtils', function() {
1288+
var inputEl, dropdownEl, $document, $sniffer, $timeout;
1289+
1290+
function assignElements(wrapElement) {
1291+
inputEl = wrapElement.find('input');
1292+
dropdownEl = wrapElement.find('ul');
1293+
element = dropdownEl.find('table');
1294+
}
1295+
1296+
beforeEach(inject(function() {
1297+
$rootScope.date = '2010-09-15T00:00:00.000';
1298+
$rootScope.isopen = true;
1299+
var wrapper = $compile('<div><input ng-model="date" datepicker-popup="MM/dd/yyyy" timeless-json-mode="true" datepicker-json-utils max-date="jsonToTicks(date) + oneDay" is-open="isopen"></div>')($rootScope);
1300+
$rootScope.$digest();
1301+
assignElements(wrapper);
1302+
}));
1303+
1304+
it('jsonToDate should be on scope and work with max-date', function() {
1305+
expect(getAllOptionsEl().eq(19).prop('disabled')).toBe(true);
1306+
});
1307+
});
1308+
12581309
describe('setting datepickerPopupConfig inside ng-if', function() {
12591310
var originalConfig = {};
12601311
beforeEach(inject(function (datepickerPopupConfig) {

0 commit comments

Comments
 (0)