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

Commit

Permalink
feat(datepicker): ng-model-options: allowInvalid support, #4694, #4837
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffrey Barrus committed Dec 9, 2015
1 parent 3658502 commit 72c43c3
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 19 deletions.
46 changes: 27 additions & 19 deletions src/datepicker/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
yearRange: 20,
minDate: null,
maxDate: null,
shortcutPropagation: false
shortcutPropagation: false,
ngModelOptions: {}
})

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

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

this.init = function(ngModelCtrl_) {
this.init = function(ngModelCtrl_, _ngModelOptions_) {
ngModelCtrl = ngModelCtrl_;

ngModelOptions = _ngModelOptions_ && _ngModelOptions_.$options || {};
ngModelCtrl.$render = function() {
self.render();
};
Expand Down Expand Up @@ -461,13 +463,15 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
customClass: '&',
shortcutPropagation: '&?'
},
require: ['uibDatepicker', '^ngModel'],
require: ['uibDatepicker', '^ngModel', '^?ngModelOptions'],
controller: 'UibDatepickerController',
controllerAs: 'datepicker',
link: function(scope, element, attrs, ctrls) {
var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
var datepickerCtrl = ctrls[0],
ngModelCtrl = ctrls[1],
ngModelOptions = ctrls[2];

datepickerCtrl.init(ngModelCtrl);
datepickerCtrl.init(ngModelCtrl, ngModelOptions);
}
};
})
Expand Down Expand Up @@ -543,19 +547,21 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
altInputFormats: []
})

.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout',
function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout) {
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', '$log',
function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, $log) {
var self = this;
var cache = {},
isHtml5DateInput = false;
var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
ngModel, $popup, altInputFormats;
ngModel, ngModelOptions, $popup, altInputFormats;

scope.watchData = {};

this.init = function(_ngModel_) {
this.init = function(_ngModel_, _ngModelOptions_) {
ngModel = _ngModel_;

ngModelOptions = _ngModelOptions_ && _ngModelOptions_.$options || {};
closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
Expand Down Expand Up @@ -605,6 +611,9 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
datepickerEl = angular.element(popupEl.children()[0]);
datepickerEl.attr('template-url', datepickerTemplateUrl);

scope.ngModelOptions = { $options: angular.extend({ allowInvalid: false }, ngModelOptions) };
datepickerEl.attr({'ng-model-options': 'ngModelOptions'});

if (isHtml5DateInput) {
if (attrs.type === 'month') {
datepickerEl.attr('datepicker-mode', '"month"');
Expand Down Expand Up @@ -826,14 +835,12 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi

if (angular.isString(viewValue)) {
var date = parseDateString(viewValue);
if (isNaN(date)) {
return undefined;
if (!isNaN(date)) {
return date;
}

return date;
}

return undefined;
return ngModelOptions && ngModelOptions.allowInvalid ? viewValue : undefined;
}

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

.directive('uibDatepickerPopup', function() {
return {
require: ['ngModel', 'uibDatepickerPopup'],
require: ['ngModel', 'uibDatepickerPopup', '^?ngModelOptions'],
controller: 'UibDatepickerPopupController',
scope: {
isOpen: '=?',
Expand All @@ -911,9 +918,10 @@ function(scope, element, attrs, $compile, $parse, $document, $rootScope, $positi
},
link: function(scope, element, attrs, ctrls) {
var ngModel = ctrls[0],
ctrl = ctrls[1];
ctrl = ctrls[1],
ngModelOptions = ctrls[2];

ctrl.init(ngModel);
ctrl.init(ngModel, ngModelOptions);
}
};
})
Expand Down
5 changes: 5 additions & 0 deletions src/datepicker/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ The datepicker has 3 modes:
* `year-range`
_(Default: `20`)_ -
Number of years displayed in year selection.

* `ng-model-options`
_(Default: {})_ -
allowInvalid support. [More on ngModelOptions](https://docs.angularjs.org/api/ng/directive/ngModelOptions).


### uib-datepicker-popup settings ###

Expand Down
27 changes: 27 additions & 0 deletions src/datepicker/test/datepicker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,33 @@ describe('datepicker', function() {
});
});

describe('ngModelOptions allowInvalid', function() {
var $sniffer, inputEl;

function changeInputValueTo(el, value) {
el.val(value);
el.trigger($sniffer.hasEvent('input') ? 'input' : 'change');
$rootScope.$digest();
}

beforeEach(inject(function(_$sniffer_) {
$sniffer = _$sniffer_;

$rootScope.date = new Date('September 30, 2010 15:30:00');
$rootScope.modelOptions = {allowInvalid: true};
element = $compile('<div><input ng-model="date" ng-model-options="modelOptions" uib-datepicker-popup></div>')($rootScope);
inputEl = element.find('input');
$rootScope.$digest();
}));


it('should update ng-model even if the date is invalid when allowInvalid is true', function() {
changeInputValueTo(inputEl, 'pizza');
expect($rootScope.date).toBe('pizza');
expect(inputEl.val()).toBe('pizza');
});
});

describe('setting datepickerPopupConfig', function() {
var originalConfig = {};
beforeEach(inject(function(uibDatepickerPopupConfig) {
Expand Down

0 comments on commit 72c43c3

Please sign in to comment.