Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 72c43c3

Browse files
author
Jeffrey Barrus
committed
feat(datepicker): ng-model-options: allowInvalid support, #4694, #4837
1 parent 3658502 commit 72c43c3

File tree

3 files changed

+59
-19
lines changed

3 files changed

+59
-19
lines changed

Diff for: src/datepicker/datepicker.js

+27-19
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
1717
yearRange: 20,
1818
minDate: null,
1919
maxDate: null,
20-
shortcutPropagation: false
20+
shortcutPropagation: false,
21+
ngModelOptions: {}
2122
})
2223

2324
.controller('UibDatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$log', 'dateFilter', 'uibDatepickerConfig', '$datepickerSuppressError', function($scope, $attrs, $parse, $interpolate, $log, dateFilter, datepickerConfig, $datepickerSuppressError) {
2425
var self = this,
25-
ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl;
26+
ngModelCtrl = { $setViewValue: angular.noop}, // nullModelCtrl;
27+
ngModelOptions = {};
2628

2729
// Modes chain
2830
this.modes = ['day', 'month', 'year'];
@@ -94,9 +96,9 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
9496
return false;
9597
};
9698

97-
this.init = function(ngModelCtrl_) {
99+
this.init = function(ngModelCtrl_, _ngModelOptions_) {
98100
ngModelCtrl = ngModelCtrl_;
99-
101+
ngModelOptions = _ngModelOptions_ && _ngModelOptions_.$options || {};
100102
ngModelCtrl.$render = function() {
101103
self.render();
102104
};
@@ -461,13 +463,15 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
461463
customClass: '&',
462464
shortcutPropagation: '&?'
463465
},
464-
require: ['uibDatepicker', '^ngModel'],
466+
require: ['uibDatepicker', '^ngModel', '^?ngModelOptions'],
465467
controller: 'UibDatepickerController',
466468
controllerAs: 'datepicker',
467469
link: function(scope, element, attrs, ctrls) {
468-
var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
470+
var datepickerCtrl = ctrls[0],
471+
ngModelCtrl = ctrls[1],
472+
ngModelOptions = ctrls[2];
469473

470-
datepickerCtrl.init(ngModelCtrl);
474+
datepickerCtrl.init(ngModelCtrl, ngModelOptions);
471475
}
472476
};
473477
})
@@ -543,19 +547,21 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
543547
altInputFormats: []
544548
})
545549

546-
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout',
547-
function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout) {
550+
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', '$log',
551+
function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, $log) {
548552
var self = this;
549553
var cache = {},
550554
isHtml5DateInput = false;
551555
var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
552556
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
553-
ngModel, $popup, altInputFormats;
557+
ngModel, ngModelOptions, $popup, altInputFormats;
554558

555559
scope.watchData = {};
556560

557-
this.init = function(_ngModel_) {
561+
this.init = function(_ngModel_, _ngModelOptions_) {
558562
ngModel = _ngModel_;
563+
564+
ngModelOptions = _ngModelOptions_ && _ngModelOptions_.$options || {};
559565
closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
560566
appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
561567
onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
@@ -605,6 +611,9 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
605611
datepickerEl = angular.element(popupEl.children()[0]);
606612
datepickerEl.attr('template-url', datepickerTemplateUrl);
607613

614+
scope.ngModelOptions = { $options: angular.extend({ allowInvalid: false }, ngModelOptions) };
615+
datepickerEl.attr({'ng-model-options': 'ngModelOptions'});
616+
608617
if (isHtml5DateInput) {
609618
if (attrs.type === 'month') {
610619
datepickerEl.attr('datepicker-mode', '"month"');
@@ -826,14 +835,12 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
826835

827836
if (angular.isString(viewValue)) {
828837
var date = parseDateString(viewValue);
829-
if (isNaN(date)) {
830-
return undefined;
838+
if (!isNaN(date)) {
839+
return date;
831840
}
832-
833-
return date;
834841
}
835842

836-
return undefined;
843+
return ngModelOptions && ngModelOptions.allowInvalid ? viewValue : undefined;
837844
}
838845

839846
function validator(modelValue, viewValue) {
@@ -899,7 +906,7 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
899906

900907
.directive('uibDatepickerPopup', function() {
901908
return {
902-
require: ['ngModel', 'uibDatepickerPopup'],
909+
require: ['ngModel', 'uibDatepickerPopup', '^?ngModelOptions'],
903910
controller: 'UibDatepickerPopupController',
904911
scope: {
905912
isOpen: '=?',
@@ -911,9 +918,10 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
911918
},
912919
link: function(scope, element, attrs, ctrls) {
913920
var ngModel = ctrls[0],
914-
ctrl = ctrls[1];
921+
ctrl = ctrls[1],
922+
ngModelOptions = ctrls[2];
915923

916-
ctrl.init(ngModel);
924+
ctrl.init(ngModel, ngModelOptions);
917925
}
918926
};
919927
})

Diff for: src/datepicker/docs/readme.md

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ The datepicker has 3 modes:
9494
* `year-range`
9595
_(Default: `20`)_ -
9696
Number of years displayed in year selection.
97+
98+
* `ng-model-options`
99+
_(Default: {})_ -
100+
allowInvalid support. [More on ngModelOptions](https://docs.angularjs.org/api/ng/directive/ngModelOptions).
101+
97102

98103
### uib-datepicker-popup settings ###
99104

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

+27
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,33 @@ describe('datepicker', function() {
12661266
});
12671267
});
12681268

1269+
describe('ngModelOptions allowInvalid', function() {
1270+
var $sniffer, inputEl;
1271+
1272+
function changeInputValueTo(el, value) {
1273+
el.val(value);
1274+
el.trigger($sniffer.hasEvent('input') ? 'input' : 'change');
1275+
$rootScope.$digest();
1276+
}
1277+
1278+
beforeEach(inject(function(_$sniffer_) {
1279+
$sniffer = _$sniffer_;
1280+
1281+
$rootScope.date = new Date('September 30, 2010 15:30:00');
1282+
$rootScope.modelOptions = {allowInvalid: true};
1283+
element = $compile('<div><input ng-model="date" ng-model-options="modelOptions" uib-datepicker-popup></div>')($rootScope);
1284+
inputEl = element.find('input');
1285+
$rootScope.$digest();
1286+
}));
1287+
1288+
1289+
it('should update ng-model even if the date is invalid when allowInvalid is true', function() {
1290+
changeInputValueTo(inputEl, 'pizza');
1291+
expect($rootScope.date).toBe('pizza');
1292+
expect(inputEl.val()).toBe('pizza');
1293+
});
1294+
});
1295+
12691296
describe('setting datepickerPopupConfig', function() {
12701297
var originalConfig = {};
12711298
beforeEach(inject(function(uibDatepickerPopupConfig) {

0 commit comments

Comments
 (0)