From f20fa4c909b0b414e2932efaace7b2f1a32f30b1 Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Tue, 29 Mar 2016 05:43:19 +0300 Subject: [PATCH 1/6] Refactor ui-date directive, fix(date): Apply the ui-date-format to the dateOptions if provided --- bower.json | 4 +- demo/index.html | 77 ++++++++++------- demo/script.js | 14 ++++ package.json | 6 +- src/date.js | 216 ++++++++++++++++++------------------------------ 5 files changed, 145 insertions(+), 172 deletions(-) create mode 100644 demo/script.js diff --git a/bower.json b/bower.json index 8f513d9..6186869 100644 --- a/bower.json +++ b/bower.json @@ -16,7 +16,7 @@ "package.json" ], "dependencies": { - "angular": "^1.3.x", - "jquery-ui": "^1.9" + "angular": "~1.5.x", + "jquery-ui": "~1.11" } } diff --git a/demo/index.html b/demo/index.html index e017cea..380375e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,18 +1,21 @@ - - - - AngularUI - Date Picker Demo - - - - - - - -
-
+ + + + AngularUI - Date Picker Demo + + + + + + +
+

Examples

+ + +

ui-date (binding options)

+
@@ -23,28 +26,38 @@
- Required date: + Required date:
The required date field is required.
- - -
- - - - - - - + + + +

ui-date (binding options)

+
+
{{myForm.smth2.$error | json}}
+ + + + +
{{ aDate1 }}
+
+ + {{getDate(aDate1)}} +
+
+ + + + +
+ + + + + + + diff --git a/demo/script.js b/demo/script.js new file mode 100644 index 0000000..c798622 --- /dev/null +++ b/demo/script.js @@ -0,0 +1,14 @@ +angular.module('MyApp', ['ui.date']) + .controller('MyCtrl', function ($scope) { + $scope.aDate = '2015-10-31'; + // $scope.aDate1 = 'Thursday, 11 October, 2012'; + // $scope.aDate1 = '2015-10-31'; + // $scope.aDate1 = "2014-08-20T00:00:00-04:00"; + $scope.aDate1 = "2016-12-28T15:58:21.162000Z"; + $scope.dateOptions = { + dateFormat: 'dd.mm.yy', + } + $scope.getDate = function(date) { + return typeof date; + } + }) \ No newline at end of file diff --git a/package.json b/package.json index a29e016..4d11f78 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,8 @@ "datepicker" ], "devDependencies": { - "angular": "^1.4.0", - "angular-mocks": "^1.4.0", + "angular": "^1.5.x", + "angular-mocks": "^1.5.0", "babel-core": "6.3.15", "babel-loader": "6.2.0", "babel-preset-es2015": "6.3.13", @@ -45,7 +45,7 @@ "expose-loader": "0.7.1", "jasmine-core": "^2.4.1", "jquery": "2.1.4", - "jquery-ui": "1.10.5", + "jquery-ui": "^1.11.4", "karma": "^0.13.15", "karma-chrome-launcher": "^0.2.2", "karma-firefox-launcher": "^0.1.7", diff --git a/src/date.js b/src/date.js index d10e388..208b026 100644 --- a/src/date.js +++ b/src/date.js @@ -3,112 +3,41 @@ import angular from 'angular'; import _datePicker from 'jquery-ui/datepicker'; // sets up jQuery with the datepicker plugin export default angular.module('ui.date', []) - .constant('uiDateConfig', {}) - .constant('uiDateFormatConfig', '') - .factory('uiDateConverter', ['uiDateFormatConfig', function(uiDateFormatConfig) { - return { - stringToDate: stringToDate, - dateToString: dateToString, - }; - - function dateToString(uiDateFormat, value) { - var dateFormat = uiDateFormat || uiDateFormatConfig; - if (value) { - if (dateFormat) { - try { - return jQuery.datepicker.formatDate(dateFormat, value); - } catch (formatException) { - return undefined; - } - } - - if (value.toISOString) { - return value.toISOString(); - } - - } - return null; - } - - function stringToDate(dateFormat, valueToParse) { - dateFormat = dateFormat || uiDateFormatConfig; - - if (angular.isDate(valueToParse) && !isNaN(valueToParse)) { - return valueToParse; - } - - if (angular.isString(valueToParse)) { - if (dateFormat) { - return jQuery.datepicker.parseDate(dateFormat, valueToParse); - } - - var isoDate = new Date(valueToParse); - return isNaN(isoDate.getTime()) ? null : isoDate; - - } - - if (angular.isNumber(valueToParse)) { - // presumably timestamp to date object - return new Date(valueToParse); - } - - return null; - } - }]) - - .directive('uiDate', ['uiDateConfig', 'uiDateConverter', function uiDateDirective(uiDateConfig, uiDateConverter) { + .constant('UI_DATE_CONFIG', {}) + .constant('UI_DATE_FORMAT', 'yy-mm-dd') + .directive('uiDate', ['UI_DATE_CONFIG','UI_DATE_FORMAT', function uiDateDirective(UI_DATE_CONFIG, UI_DATE_FORMAT) { return { require: '?ngModel', - link: function link(scope, element, attrs, controller) { - - var $element = jQuery(element); + priority: 1, + link: function link(scope, element, attrs, ngModelCtrl) { + var modelDateFormat = attrs.uiDateFormat; + var $element = angular.element(element); var getOptions = function() { - return angular.extend({}, uiDateConfig, scope.$eval(attrs.uiDate)); + return angular.extend({}, UI_DATE_CONFIG, scope.$eval(attrs.uiDate)); }; + var initDateWidget = function() { var showing = false; var opts = getOptions(); - function setVal(forcedUpdate) { - var keys = ['Hours', 'Minutes', 'Seconds', 'Milliseconds']; - var isDate = angular.isDate(controller.$modelValue); - var preserve = {}; - - if (!forcedUpdate && isDate && controller.$modelValue.toDateString() === $element.datepicker('getDate').toDateString()) { - return; - } - - if (isDate) { - angular.forEach(keys, function(key) { - preserve[key] = controller.$modelValue['get' + key](); - }); - } - - var newViewValue = $element.datepicker('getDate'); - - if (isDate) { - angular.forEach(keys, (key) => { - newViewValue['set' + key](preserve[key]); - }); - } - - controller.$setViewValue(newViewValue); + function setVal(date) { + ngModelCtrl.$setViewValue(new Date(date)); + ngModelCtrl.$render(); } - // If we have a controller (i.e. ngModelController) then wire it up - if (controller) { + // If we have a ngModelCtrl (i.e. ngModelController) then wire it up + if (ngModelCtrl) { // Set the view value in a $apply block when users selects // (calling directive user's function too if provided) var _onSelect = opts.onSelect || angular.noop; opts.onSelect = function(value, picker) { - scope.$apply(function() { - showing = true; - setVal(); - $element.blur(); - _onSelect(value, picker, $element); - }); + showing = true; + value = parseDateWithCurrentFormat(value); + setVal(value); + $element.blur(); + _onSelect(value, picker, $element); }; var _beforeShow = opts.beforeShow || angular.noop; @@ -120,7 +49,7 @@ export default angular.module('ui.date', []) var _onClose = opts.onClose || angular.noop; opts.onClose = function(value, picker) { showing = false; - $element.focus(); + // $element.focus(); _onClose(value, picker, $element); }; @@ -131,36 +60,23 @@ export default angular.module('ui.date', []) }); $element.off('blur.datepicker').on('blur.datepicker', function() { - if (!showing) { - scope.$apply(function() { - $element.datepicker('setDate', $element.datepicker('getDate')); - setVal(); - }); - } + if (!showing) {} }); - controller.$validators.uiDateValidator = function uiDateValidator(modelValue, viewValue) { - return viewValue === null - || viewValue === '' - || angular.isDate(uiDateConverter.stringToDate(attrs.uiDateFormat, viewValue)); - }; - controller.$parsers.push(function uiDateParser(valueToParse) { - return uiDateConverter.stringToDate(attrs.uiDateFormat, valueToParse); - }); // Update the date picker when the model changes - controller.$render = function() { - // Force a render to override whatever is in the input text box - if (angular.isDate(controller.$modelValue) === false && angular.isString(controller.$modelValue)) { - controller.$modelValue = uiDateConverter.stringToDate(attrs.uiDateFormat, controller.$modelValue); - } - $element.datepicker('setDate', controller.$modelValue); + ngModelCtrl.$render = function() { + $element.datepicker('setDate', new Date(ngModelCtrl.$modelValue)); }; + + + ngModelCtrl.$parsers.push(uiDateParser); + ngModelCtrl.$validators.uiDateValidator = uiDateValidator; + ngModelCtrl.$formatters.push(uiDateFormatter); } - // Check if the $element already has a datepicker. - // + // Check if the $element already has a datepicker. if ($element.data('datepicker')) { // Updates the datepicker options $element.datepicker('option', opts); @@ -176,33 +92,63 @@ export default angular.module('ui.date', []) }); } - if (controller) { - controller.$render(); - // Update the model with the value from the datepicker after parsed - setVal(true); + if (ngModelCtrl) { + setVal(Date.parse(ngModelCtrl.$modelValue)); + } + + + function uiDateParser(valueToParse) { + var parsedDate = Date.parse(valueToParse); + + if (isNaN(parsedDate) && valueToParse.length) { + try { + parsedDate = Date.parse(parseDateWithCurrentFormat(valueToParse)); + } + catch (error) {} + } + + return modelDateFormat && !isNaN(parsedDate) ? + $.datepicker.formatDate(modelDateFormat, new Date(parsedDate)) : + parsedDate; + } + + + function uiDateValidator(modelValue, viewValue) { + console.warn('uiDateValidator , modelValue, viewValue', modelValue, viewValue); + var isValidDate = !isNaN(Date.parse(viewValue)) || !isNaN(modelValue); + + if (modelDateFormat && viewValue.length) { + try { + console.info('uiDateValidator try', viewValue); + isValidDate = !isNaN(Date.parse(parseDateWithCurrentFormat(viewValue))); + } + catch (error) {} + } + + console.info('uiDateValidator isValidDate', isValidDate); + + return viewValue === null + || viewValue === '' + || isValidDate; + } + + + function uiDateFormatter(modelToFormat) { + modelToFormat = new Date(modelToFormat); + modelToFormat = $.datepicker.formatDate(opts.dateFormat || UI_DATE_FORMAT, modelToFormat); + return modelToFormat; + } + + + function parseDateWithCurrentFormat(valueToParse) { + var currentDateFormat = $element.datepicker( "option", "dateFormat" ); + return $.datepicker.parseDate(currentDateFormat, valueToParse); } }; // Watch for changes to the directives options scope.$watch(getOptions, initDateWidget, true); - }, - }; - }]) - .directive('uiDateFormat', ['uiDateConverter', function(uiDateConverter) { - return { - require: 'ngModel', - link: function(scope, element, attrs, modelCtrl) { - var dateFormat = attrs.uiDateFormat; - - // Use the datepicker with the attribute value as the dateFormat string to convert to and from a string - modelCtrl.$formatters.unshift(function(value) { - return uiDateConverter.stringToDate(dateFormat, value); - }); - - modelCtrl.$parsers.push(function(value) { - return uiDateConverter.dateToString(dateFormat, value); - }); }, }; - }]); + }]); \ No newline at end of file From ae0fce1eaba6f8393b2d14df5cd1a832030f9bf6 Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Tue, 29 Mar 2016 20:30:27 +0300 Subject: [PATCH 2/6] fix input data formats, refactor --- demo/index.html | 31 ++++++++++++---------- demo/script.js | 4 +-- src/date.js | 69 ++++++++++++++++++++++--------------------------- 3 files changed, 50 insertions(+), 54 deletions(-) diff --git a/demo/index.html b/demo/index.html index 380375e..37b294d 100644 --- a/demo/index.html +++ b/demo/index.html @@ -16,30 +16,33 @@

Examples

ui-date (binding options)

- - + + -
{{ aDate }}
-
- Read only -
+ + + + -
- Required date: -
- The required date field is required. -
-
+ + + + + +

ui-date (binding options)

{{myForm.smth2.$error | json}}
+
{{myForm.smth2.$modelValue | json}}
- - + + + +
{{ aDate1 }}
diff --git a/demo/script.js b/demo/script.js index c798622..1560fac 100644 --- a/demo/script.js +++ b/demo/script.js @@ -2,9 +2,9 @@ angular.module('MyApp', ['ui.date']) .controller('MyCtrl', function ($scope) { $scope.aDate = '2015-10-31'; // $scope.aDate1 = 'Thursday, 11 October, 2012'; - // $scope.aDate1 = '2015-10-31'; + $scope.aDate1 = '2015-10-31'; // $scope.aDate1 = "2014-08-20T00:00:00-04:00"; - $scope.aDate1 = "2016-12-28T15:58:21.162000Z"; + // $scope.aDate1 = "2016-12-28T15:58:21.162000Z"; $scope.dateOptions = { dateFormat: 'dd.mm.yy', } diff --git a/src/date.js b/src/date.js index 208b026..eaf4d54 100644 --- a/src/date.js +++ b/src/date.js @@ -23,7 +23,7 @@ export default angular.module('ui.date', []) var opts = getOptions(); function setVal(date) { - ngModelCtrl.$setViewValue(new Date(date)); + ngModelCtrl.$setViewValue(initialParser(date)); ngModelCtrl.$render(); } @@ -67,7 +67,16 @@ export default angular.module('ui.date', []) // Update the date picker when the model changes ngModelCtrl.$render = function() { - $element.datepicker('setDate', new Date(ngModelCtrl.$modelValue)); + if (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue)) { + $element.datepicker('setDate', null); + } + else if (angular.isString(ngModelCtrl.$modelValue)) { + return setVal(Date.parse(ngModelCtrl.$modelValue)); + } + else { + $element.datepicker('setDate', new Date(ngModelCtrl.$modelValue)); + } + }; @@ -92,57 +101,41 @@ export default angular.module('ui.date', []) }); } - if (ngModelCtrl) { - setVal(Date.parse(ngModelCtrl.$modelValue)); + if (ngModelCtrl && !ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue)) { + setVal(angular.isString(ngModelCtrl.$modelValue) ? Date.parse(ngModelCtrl.$modelValue) : ngModelCtrl.$modelValue); } - - function uiDateParser(valueToParse) { - var parsedDate = Date.parse(valueToParse); - - if (isNaN(parsedDate) && valueToParse.length) { - try { - parsedDate = Date.parse(parseDateWithCurrentFormat(valueToParse)); - } - catch (error) {} - } - - return modelDateFormat && !isNaN(parsedDate) ? - $.datepicker.formatDate(modelDateFormat, new Date(parsedDate)) : - parsedDate; + function initialParser(date) { + var dateFormat = $element.datepicker( "option", "dateFormat" ); + return $.datepicker.formatDate(dateFormat, new Date(date)); } + function uiDateParser(valueToParse) { + return parseDateWithCurrentFormat(valueToParse); + } + + function uiDateValidator(modelValue, viewValue) { - console.warn('uiDateValidator , modelValue, viewValue', modelValue, viewValue); - var isValidDate = !isNaN(Date.parse(viewValue)) || !isNaN(modelValue); - - if (modelDateFormat && viewValue.length) { - try { - console.info('uiDateValidator try', viewValue); - isValidDate = !isNaN(Date.parse(parseDateWithCurrentFormat(viewValue))); - } - catch (error) {} - } - - console.info('uiDateValidator isValidDate', isValidDate); - - return viewValue === null - || viewValue === '' - || isValidDate; + return modelValue !== null || viewValue === ''; } function uiDateFormatter(modelToFormat) { - modelToFormat = new Date(modelToFormat); - modelToFormat = $.datepicker.formatDate(opts.dateFormat || UI_DATE_FORMAT, modelToFormat); return modelToFormat; } function parseDateWithCurrentFormat(valueToParse) { - var currentDateFormat = $element.datepicker( "option", "dateFormat" ); - return $.datepicker.parseDate(currentDateFormat, valueToParse); + var dateFormat = $element.datepicker( "option", "dateFormat" ); + var formattedDate = $.datepicker.formatDate(dateFormat, new Date()); + + if (formattedDate.length === valueToParse.length) { + return Date.parse($.datepicker.parseDate(dateFormat, valueToParse)); + } + else { + return null; + } } }; From 20aef6faaef52c6f5189381e997e521d0e0b3481 Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Thu, 31 Mar 2016 17:29:18 +0300 Subject: [PATCH 3/6] Refactor ui-date directive, fix(date): Apply the ui-date-format to the dateOptions if provided --- src/date.js | 311 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 207 insertions(+), 104 deletions(-) diff --git a/src/date.js b/src/date.js index eaf4d54..6c651d7 100644 --- a/src/date.js +++ b/src/date.js @@ -1,147 +1,250 @@ -import jQuery from 'jquery'; import angular from 'angular'; import _datePicker from 'jquery-ui/datepicker'; // sets up jQuery with the datepicker plugin export default angular.module('ui.date', []) - .constant('UI_DATE_CONFIG', {}) - .constant('UI_DATE_FORMAT', 'yy-mm-dd') - .directive('uiDate', ['UI_DATE_CONFIG','UI_DATE_FORMAT', function uiDateDirective(UI_DATE_CONFIG, UI_DATE_FORMAT) { + .service('uiDateHelper', function () { + //TODO(improve) separate storage by scope.id [resolve possible issues when use same modelName in different scopes] + var storage = { + models: {}, + formats: {}, + counts: {} + }; + this.initUiDate = function(modelName, options, format) { + if (!storage.models[modelName]) { + storage.models[modelName] = options || true; + storage.formats[modelName] = format; + storage.counts[modelName] = 1; + } + else if (storage.models[modelName] !== options) { + throw Error('In ui-date options obj value isn\'t the same for all ' + + 'ngModel\'s with variable: "' + modelName +'"'); + } + else if (storage.formats[modelName] !== format) { + throw Error('In ui-date-format format value isn\'t the same for all ' + + 'ngModel\'s with variable: "' + modelName +'"'); + } + else { + storage.counts[modelName] += 1; + } + }; + this.clearUiDate = function(modelName) { + if (storage.counts[modelName] > 1) { + storage.counts[modelName] -= 1; + } + else { + delete storage.counts[modelName]; + delete storage.formats[modelName]; + delete storage.models[modelName]; + } + } + }) + .directive('uiDate', ['$parse', 'uiDateHelper', function uiDateDirective($parse, uiDateHelper) { return { require: '?ngModel', - priority: 1, link: function link(scope, element, attrs, ngModelCtrl) { var modelDateFormat = attrs.uiDateFormat; - var $element = angular.element(element); - - var getOptions = function() { - return angular.extend({}, UI_DATE_CONFIG, scope.$eval(attrs.uiDate)); - }; - - var initDateWidget = function() { - var showing = false; - var opts = getOptions(); - - function setVal(date) { - ngModelCtrl.$setViewValue(initialParser(date)); - ngModelCtrl.$render(); - } - - // If we have a ngModelCtrl (i.e. ngModelController) then wire it up - if (ngModelCtrl) { - // Set the view value in a $apply block when users selects - // (calling directive user's function too if provided) - var _onSelect = opts.onSelect || angular.noop; - opts.onSelect = function(value, picker) { - showing = true; - value = parseDateWithCurrentFormat(value); - setVal(value); - $element.blur(); - _onSelect(value, picker, $element); - }; - - var _beforeShow = opts.beforeShow || angular.noop; - opts.beforeShow = function(input, picker) { - showing = true; - _beforeShow(input, picker, $element); - }; - - var _onClose = opts.onClose || angular.noop; - opts.onClose = function(value, picker) { - showing = false; - // $element.focus(); - _onClose(value, picker, $element); - }; - - element.on('focus', function(focusEvent) { - if (attrs.readonly) { - focusEvent.stopImmediatePropagation(); - } - }); + var modelGetter = $parse(attrs.ngModel); + var modelSetter = modelGetter.assign; + + init(); - $element.off('blur.datepicker').on('blur.datepicker', function() { - if (!showing) {} - }); + //TODO Set watcher on ng-model scope value and re-init(convert time string to Date instance) when change - // Update the date picker when the model changes - ngModelCtrl.$render = function() { - if (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue)) { - $element.datepicker('setDate', null); - } - else if (angular.isString(ngModelCtrl.$modelValue)) { - return setVal(Date.parse(ngModelCtrl.$modelValue)); - } - else { - $element.datepicker('setDate', new Date(ngModelCtrl.$modelValue)); - } + //- IMPLEMENTATION + function init() { + if (!ngModelCtrl) { + //just init datepicker on element + datepicker(getOptions()); + return; + } - }; + uiDateHelper.initUiDate(attrs.ngModel, getOptions(), modelDateFormat); + var value = modelGetter(scope); + if (value && !(value instanceof Date)) { + console.warn('The ng-model for ui-date have to be a Date instance. ' + + 'Currently the model is a: ' + typeof value); + console.warn('Trying convert to new Date("' + value + '")'); - ngModelCtrl.$parsers.push(uiDateParser); - ngModelCtrl.$validators.uiDateValidator = uiDateValidator; - ngModelCtrl.$formatters.push(uiDateFormatter); + parseNonDateValue(value) } + + scope.$watch(getOptions, setDatepicker, true); + attrs.$observe('uiDateFormat', function (dateOptions) { + modelDateFormat = dateOptions; + }); + + + //setTimeout is used to call following code after $watch initial execute of + // setDatepicker and datepicker is applied for element + setTimeout(function () { + var dateFormat = element.datepicker('option', 'dateFormat'); + var formattedDate = $.datepicker.formatDate(dateFormat, ngModelCtrl.$modelValue); + + //initial onSelect emulate + element.datepicker('setDate', formattedDate); + scope.$applyAsync(function () { + ngModelCtrl.$setViewValue(formattedDate); + }); + + + ngModelCtrl.$render = renderFn; + ngModelCtrl.$parsers.push(parser); + // ngModelCtrl.$validators.uiDateValidator = uiDateValidator; + ngModelCtrl.$formatters.push(formatter); + }, 0) + + } + + + function parseNonDateValue(value) { + var dateInstance = new Date(value); + if (dateInstance === 'Invalid Date') { + throw Error('Unable to parse ng-model for ui-date'); + } + else { + modelSetter(scope, dateInstance); + } + } + + + function getOptions() { + return scope.$eval(attrs.uiDate); + } + + + function setDatepicker(opts) { + // we must copy options to prevent sharing options like 'onSelect' between scope.dateFormat which + // might be used for different ng-model's + var opts = opts ? angular.copy(opts) : {}; + + // Set the view value in a $apply block when users selects + // (calling directive user's function too if provided) + var _onSelect = opts.onSelect || angular.noop; + opts.onSelect = function (dateText, picker) { + scope.$apply(function () { + ngModelCtrl.$setViewValue(dateText); + }); + element.blur(); + _onSelect(dateText, picker, element); + }; + + var _beforeShow = opts.beforeShow || angular.noop; + opts.beforeShow = function (input, picker) { + _beforeShow(input, picker, element); + }; + + var _onClose = opts.onClose || angular.noop; + opts.onClose = function (dateText, picker) { + _onClose(dateText, picker, element); + }; + + datepicker(opts); + } + + + function datepicker(opts) { // Check if the $element already has a datepicker. - if ($element.data('datepicker')) { + if (element.data('datepicker')) { // Updates the datepicker options - $element.datepicker('option', opts); - $element.datepicker('refresh'); + element.datepicker('option', opts); + element.datepicker('refresh'); } else { // Creates the new datepicker widget - $element.datepicker(opts); + element.datepicker(opts); // Cleanup on destroy, prevent memory leaking - $element.on('$destroy', function() { - $element.datepicker('hide'); - $element.datepicker('destroy'); + element.on('$destroy', function () { + uiDateHelper.clearUiDate(attrs.ngModel); + element.off('focus'); + element.datepicker('hide'); + element.datepicker('destroy'); }); } - if (ngModelCtrl && !ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue)) { - setVal(angular.isString(ngModelCtrl.$modelValue) ? Date.parse(ngModelCtrl.$modelValue) : ngModelCtrl.$modelValue); - } + element.on('focus', function (focusEvent) { + if (attrs.readonly) { + focusEvent.stopImmediatePropagation(); + } + }); + + } - function initialParser(date) { - var dateFormat = $element.datepicker( "option", "dateFormat" ); - return $.datepicker.formatDate(dateFormat, new Date(date)); + + function renderFn() { + if (ngModelCtrl.$viewValue) { + var dateFormat = element.datepicker('option', 'dateFormat'); + var getDate = $.datepicker.parseDate(dateFormat, ngModelCtrl.$viewValue); + element.datepicker('setDate', getDate); + } + else if (ngModelCtrl.$viewValue === '') { + element.datepicker('setDate', null); } + } + + function parser(viewValue) { + var dateFormat = element.datepicker('option', 'dateFormat'); + var validatedDate; - function uiDateParser(valueToParse) { - return parseDateWithCurrentFormat(valueToParse); + if (ngModelCtrl.$isEmpty(viewValue)) { + return viewValue; } - - - function uiDateValidator(modelValue, viewValue) { - return modelValue !== null || viewValue === ''; + + if (modelDateFormat) { + validatedDate = validateDate(dateFormat, viewValue); + //here we going to format our value with modelDateFormat + return validatedDate ? $.datepicker.formatDate(modelDateFormat, new Date(validatedDate)) : validatedDate; + } + else { + validatedDate = validateDate(dateFormat, viewValue); + return validatedDate ? viewValue : validatedDate; } + } + - function uiDateFormatter(modelToFormat) { - return modelToFormat; + function validateDate(format, date) { + try { + ngModelCtrl.$setValidity(attrs.ngModel + '_datePicker', true); + return $.datepicker.parseDate(format, date); } + catch (error) { + // console.warn('error', error); + ngModelCtrl.$setValidity(attrs.ngModel + '_datePicker', false); + return undefined; + } + } - function parseDateWithCurrentFormat(valueToParse) { - var dateFormat = $element.datepicker( "option", "dateFormat" ); - var formattedDate = $.datepicker.formatDate(dateFormat, new Date()); + function formatter(modelValue) { + var dateFormat = element.datepicker('option', 'dateFormat'); + var validatedDate; - if (formattedDate.length === valueToParse.length) { - return Date.parse($.datepicker.parseDate(dateFormat, valueToParse)); - } - else { - return null; - } + if (typeof modelValue === 'undefined') { //some other directive with same model + element.datepicker('setDate', null); } - }; - // Watch for changes to the directives options - scope.$watch(getOptions, initDateWidget, true); + if (ngModelCtrl.$isEmpty(modelValue)) { + return modelValue; + } - }, - }; + //revert value from formatted by parser(modelDateFormat is used for $viewModel format) to datepicker opts view + if (modelDateFormat) { + validatedDate = validateDate(modelDateFormat, modelValue); + return validatedDate ? $.datepicker.formatDate(dateFormat, new Date(validatedDate)) : validatedDate + } + else { + validatedDate = validateDate(dateFormat, modelValue); + return validatedDate ? modelValue : validatedDate; + } + + } + + } + } }]); \ No newline at end of file From e0b3a5c9ee20cb78d699860b60d6a95d5cd301b2 Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Mon, 4 Apr 2016 16:45:51 +0300 Subject: [PATCH 4/6] Refactor ui-date directive, fix(date): Apply the ui-date-format to the dateOptions if provided --- src/date.js | 121 +++++++++++++++++++----------- src/date.spec.js | 188 ++++++++++++++++++++++++++--------------------- 2 files changed, 180 insertions(+), 129 deletions(-) diff --git a/src/date.js b/src/date.js index 6c651d7..ac98921 100644 --- a/src/date.js +++ b/src/date.js @@ -1,15 +1,16 @@ +import $ from 'jquery'; import angular from 'angular'; import _datePicker from 'jquery-ui/datepicker'; // sets up jQuery with the datepicker plugin export default angular.module('ui.date', []) .service('uiDateHelper', function () { - //TODO(improve) separate storage by scope.id [resolve possible issues when use same modelName in different scopes] + //TODO(edge case) separate storage by scope.id [resolve possible issues when use same modelName in different scopes] var storage = { models: {}, formats: {}, counts: {} }; - this.initUiDate = function(modelName, options, format) { + this.initUiDate = function (modelName, options, format) { if (!storage.models[modelName]) { storage.models[modelName] = options || true; storage.formats[modelName] = format; @@ -17,18 +18,18 @@ export default angular.module('ui.date', []) } else if (storage.models[modelName] !== options) { throw Error('In ui-date options obj value isn\'t the same for all ' + - 'ngModel\'s with variable: "' + modelName +'"'); + 'ngModel\'s with variable: "' + modelName + '"'); } else if (storage.formats[modelName] !== format) { throw Error('In ui-date-format format value isn\'t the same for all ' + - 'ngModel\'s with variable: "' + modelName +'"'); + 'ngModel\'s with variable: "' + modelName + '"'); } else { storage.counts[modelName] += 1; } }; - this.clearUiDate = function(modelName) { + this.clearUiDate = function (modelName) { if (storage.counts[modelName] > 1) { storage.counts[modelName] -= 1; } @@ -43,14 +44,14 @@ export default angular.module('ui.date', []) return { require: '?ngModel', link: function link(scope, element, attrs, ngModelCtrl) { - var modelDateFormat = attrs.uiDateFormat; + var modelDateFormat = attrs.uiDateFormat; //format model + var dateFormat; //format view(default $.datepicker value or provided as option) var modelGetter = $parse(attrs.ngModel); var modelSetter = modelGetter.assign; - - init(); + var showing = false; - //TODO Set watcher on ng-model scope value and re-init(convert time string to Date instance) when change + init(); //- IMPLEMENTATION @@ -62,13 +63,10 @@ export default angular.module('ui.date', []) } uiDateHelper.initUiDate(attrs.ngModel, getOptions(), modelDateFormat); + var value = modelGetter(scope); if (value && !(value instanceof Date)) { - console.warn('The ng-model for ui-date have to be a Date instance. ' + - 'Currently the model is a: ' + typeof value); - console.warn('Trying convert to new Date("' + value + '")'); - parseNonDateValue(value) } @@ -78,36 +76,53 @@ export default angular.module('ui.date', []) modelDateFormat = dateOptions; }); + setDatepicker(getOptions(), true); - //setTimeout is used to call following code after $watch initial execute of - // setDatepicker and datepicker is applied for element - setTimeout(function () { - var dateFormat = element.datepicker('option', 'dateFormat'); - var formattedDate = $.datepicker.formatDate(dateFormat, ngModelCtrl.$modelValue); - //initial onSelect emulate - element.datepicker('setDate', formattedDate); - scope.$applyAsync(function () { - ngModelCtrl.$setViewValue(formattedDate); - }); + ngModelCtrl.$render = renderFn; + ngModelCtrl.$parsers.push(parser); + ngModelCtrl.$formatters.push(formatter); + + //ngModel value change from outside detection + scope.$watch(attrs.ngModel, function (date) { + if (typeof date === 'boolean') { + throw Error('Boolean isn\'t a valid date type'); + } + + if (date && !validateDate(modelDateFormat || null, date)) { + if (!(date instanceof Date)) { + setDateToModel(parseNonDateValue(date)); + } + else { + setDateToModel(date); + } + } + }); + + } - ngModelCtrl.$render = renderFn; - ngModelCtrl.$parsers.push(parser); - // ngModelCtrl.$validators.uiDateValidator = uiDateValidator; - ngModelCtrl.$formatters.push(formatter); - }, 0) + function setDateToModel(date) { + var formattedDate = $.datepicker.formatDate(dateFormat, date); + //initial onSelect emulate + element.datepicker('setDate', formattedDate); + scope.$applyAsync(function () { + ngModelCtrl.$setViewValue(formattedDate); + }); } function parseNonDateValue(value) { + console.warn('The ng-model for ui-date have to be a Date instance. ' + + 'Currently the model is a: ' + typeof value); + console.warn('Trying convert to new Date(' + value + ')'); var dateInstance = new Date(value); if (dateInstance === 'Invalid Date') { throw Error('Unable to parse ng-model for ui-date'); } else { - modelSetter(scope, dateInstance); + return modelSetter(scope, dateInstance); } } @@ -117,7 +132,10 @@ export default angular.module('ui.date', []) } - function setDatepicker(opts) { + function setDatepicker(opts, oldOpts) { + if (opts === oldOpts) { + return; + } // we must copy options to prevent sharing options like 'onSelect' between scope.dateFormat which // might be used for different ng-model's var opts = opts ? angular.copy(opts) : {}; @@ -127,19 +145,22 @@ export default angular.module('ui.date', []) var _onSelect = opts.onSelect || angular.noop; opts.onSelect = function (dateText, picker) { scope.$apply(function () { + showing = true; ngModelCtrl.$setViewValue(dateText); + element.blur(); + _onSelect(dateText, picker, element); }); - element.blur(); - _onSelect(dateText, picker, element); }; var _beforeShow = opts.beforeShow || angular.noop; opts.beforeShow = function (input, picker) { + showing = true; _beforeShow(input, picker, element); }; var _onClose = opts.onClose || angular.noop; opts.onClose = function (dateText, picker) { + showing = false; _onClose(dateText, picker, element); }; @@ -166,18 +187,28 @@ export default angular.module('ui.date', []) }); } + dateFormat = element.datepicker('option', 'dateFormat'); + element.on('focus', function (focusEvent) { if (attrs.readonly) { focusEvent.stopImmediatePropagation(); } }); + element.off('blur.datepicker').on('blur.datepicker', function() { + if (!showing) { + scope.$apply(function() { + element.datepicker('setDate', element.datepicker('getDate')); + ngModelCtrl.$render(); + }); + } + }); + } function renderFn() { if (ngModelCtrl.$viewValue) { - var dateFormat = element.datepicker('option', 'dateFormat'); var getDate = $.datepicker.parseDate(dateFormat, ngModelCtrl.$viewValue); element.datepicker('setDate', getDate); } @@ -186,9 +217,8 @@ export default angular.module('ui.date', []) } } - + function parser(viewValue) { - var dateFormat = element.datepicker('option', 'dateFormat'); var validatedDate; if (ngModelCtrl.$isEmpty(viewValue)) { @@ -201,8 +231,7 @@ export default angular.module('ui.date', []) return validatedDate ? $.datepicker.formatDate(modelDateFormat, new Date(validatedDate)) : validatedDate; } else { - validatedDate = validateDate(dateFormat, viewValue); - return validatedDate ? viewValue : validatedDate; + return validateDate(dateFormat, viewValue); } } @@ -211,7 +240,12 @@ export default angular.module('ui.date', []) function validateDate(format, date) { try { ngModelCtrl.$setValidity(attrs.ngModel + '_datePicker', true); - return $.datepicker.parseDate(format, date); + if (format === null && date instanceof Date) { + return date; + } + else { + return $.datepicker.parseDate(format, date); + } } catch (error) { // console.warn('error', error); @@ -222,15 +256,14 @@ export default angular.module('ui.date', []) function formatter(modelValue) { - var dateFormat = element.datepicker('option', 'dateFormat'); var validatedDate; if (typeof modelValue === 'undefined') { //some other directive with same model element.datepicker('setDate', null); } - if (ngModelCtrl.$isEmpty(modelValue)) { - return modelValue; + if (ngModelCtrl.$isEmpty(modelValue) || typeof modelValue === 'boolean') { + return '';//modelValue } //revert value from formatted by parser(modelDateFormat is used for $viewModel format) to datepicker opts view @@ -239,12 +272,12 @@ export default angular.module('ui.date', []) return validatedDate ? $.datepicker.formatDate(dateFormat, new Date(validatedDate)) : validatedDate } else { - validatedDate = validateDate(dateFormat, modelValue); - return validatedDate ? modelValue : validatedDate; + validatedDate = validateDate(null, modelValue); + return validatedDate ? $.datepicker.formatDate(dateFormat, new Date(modelValue)) : validatedDate; } } - + } } }]); \ No newline at end of file diff --git a/src/date.spec.js b/src/date.spec.js index 1f575c1..3230dea 100644 --- a/src/date.spec.js +++ b/src/date.spec.js @@ -313,7 +313,7 @@ describe('uiDate', function() { inject(function($compile, $rootScope) { var element; element = $compile('
')($rootScope); - expect(element.data('datepicker')).toBeUndefined(); + // expect(element.data('datepicker')).toBeUndefined(); ? why datepicker should be Undefined right after initialization? $rootScope.$apply(); expect(element.children().length).toBe(1); element.remove(); @@ -393,61 +393,66 @@ describe('uiDateFormat', function() { beforeEach(module('ui.date')); describe('$formatting', function() { - it('should parse the date correctly from an ISO string', function() { - inject(function($compile, $rootScope) { - var aDate, aDateString, element; - aDate = new Date(2012, 8, 17); - aDateString = aDate.toISOString(); - - element = $compile('')($rootScope); - $rootScope.x = aDateString; - $rootScope.$digest(); - - // Check that the model has not been altered - expect($rootScope.x).toEqual(aDateString); - // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(aDate); - }); - }); + //TODO(consider) logic change - now we convert all inputs to Date object, if user wants store ISO string or other + //TODO(consider) format(string) is could be achieved by ui-date-format + // it('should parse the date correctly from an ISO string', function() { + // inject(function($compile, $rootScope) { + // var aDate, aDateString, element; + // aDate = new Date(2012, 8, 17); + // aDateString = aDate.toISOString(); + // + // element = $compile('')($rootScope); + // $rootScope.x = aDateString; + // $rootScope.$digest(); + // + // // Check that the model has not been altered + // expect($rootScope.x).toEqual(aDateString); + // // Check that the viewValue has been parsed correctly + // expect(element.controller('ngModel').$viewValue).toEqual(aDate); + // }); + // }); it('should parse the date correctly from a custom string', function() { inject(function($compile, $rootScope) { - var aDate = new Date(2012, 9, 11); + // var aDate = new Date(2012, 9, 11); var aDateString = 'Thursday, 11 October, 2012'; - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); $rootScope.x = aDateString; $rootScope.$digest(); // Check that the model has not been altered expect($rootScope.x).toEqual(aDateString); // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(aDate); + // expect(element.controller('ngModel').$viewValue).toEqual(aDate); TODO $viewValue will be formatted by datepicker opts or by default + + //check if $modelValue has ui-date-format format + expect(element.controller('ngModel').$modelValue).toEqual(aDateString); }); }); it('should handle unusual model values', function() { inject(function($compile, $rootScope) { - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); - $rootScope.x = false; - $rootScope.$digest(); - // Check that the model has not been altered - expect($rootScope.x).toEqual(false); - // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(null); + // $rootScope.x = false; + // $rootScope.$digest(); + // // Check that the model has not been altered + // expect($rootScope.x).toEqual(false); + // // Check that the viewValue has been parsed correctly + // expect(element.controller('ngModel').$viewValue).toEqual(''); $rootScope.x = undefined; $rootScope.$digest(); // Check that the model has not been altered expect($rootScope.x).toBeUndefined(); // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(null); + expect(element.controller('ngModel').$viewValue).toEqual(''); $rootScope.x = null; $rootScope.$digest(); // Check that the model has not been altered expect($rootScope.x).toBeNull(); // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(null); + expect(element.controller('ngModel').$viewValue).toEqual(''); }); }); @@ -476,24 +481,25 @@ describe('uiDateFormat', function() { }); describe('$parsing', function() { - it('should format a selected date correctly to an ISO string', function() { - inject(function($compile, $rootScope) { - var aDate = new Date(2012, 8, 17); - var aDateString = aDate.toISOString(); - var element = $compile('')($rootScope); - $rootScope.$digest(); - - element.controller('ngModel').$setViewValue(aDate); - // Check that the model is updated correctly - expect($rootScope.x).toEqual(aDateString); - // Check that the $viewValue has not been altered - expect(element.controller('ngModel').$viewValue).toEqual(aDate); - }); - }); + //Logic breaking change, now ngModel convert everything into Date instance + // it('should format a selected date correctly to an ISO string', function() { + // inject(function($compile, $rootScope) { + // var aDate = new Date(2012, 8, 17); + // var aDateString = aDate.toISOString(); + // var element = $compile('')($rootScope); + // $rootScope.$digest(); + // + // element.controller('ngModel').$setViewValue(aDate); + // // Check that the model is updated correctly + // expect($rootScope.x).toEqual(aDateString); + // // Check that the $viewValue has not been altered + // expect(element.controller('ngModel').$viewValue).toEqual(aDate); + // }); + // }); it('should not throw when a user types in an incomplete value', function() { inject(function($compile, $rootScope) { - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); var ngModel = element.controller('ngModel'); expect(function incompleteValue() { ngModel.$setViewValue('2015-'); @@ -502,21 +508,22 @@ describe('uiDateFormat', function() { }); }); - it('should convert empty strings to null', inject(function($compile, $rootScope) { - var element = $compile('')($rootScope); - element.controller('ngModel').$setViewValue(''); - $rootScope.$digest(); - expect($rootScope.x).toBeNull(); - - element = $compile('')($rootScope); - element.controller('ngModel').$setViewValue(''); - $rootScope.$digest(); - expect($rootScope.x).toBeNull(); - })); + //Logic breaking change - all non-date values now cause empty string value in $viewValue + // it('should convert empty strings to null', inject(function($compile, $rootScope) { + // var element = $compile('')($rootScope); + // element.controller('ngModel').$setViewValue(''); + // $rootScope.$digest(); + // expect($rootScope.x).toBeNull(); + // + // element = $compile('')($rootScope); + // element.controller('ngModel').$setViewValue(''); + // $rootScope.$digest(); + // expect($rootScope.x).toBeNull(); + // })); it('should not freak out on invalid values', function() { inject(function($compile, $rootScope) { - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); $rootScope.$digest(); element.controller('ngModel').$setViewValue('abcdef'); @@ -528,14 +535,18 @@ describe('uiDateFormat', function() { var format = 'DD, d MM, yy'; var aDate = new Date(2012, 9, 11); var aDateString = 'Thursday, 11 October, 2012'; - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); + + $rootScope.x = aDate; + $rootScope.$digest(); $rootScope.$digest(); - element.controller('ngModel').$setViewValue(aDate); // Check that the model is updated correctly expect($rootScope.x).toEqual(aDateString); // Check that the $viewValue has not been altered - expect(element.controller('ngModel').$viewValue).toEqual(aDate); + var dateFormat = element.datepicker('option', 'dateFormat'); + var dateObj = $.datepicker.formatDate(dateFormat, aDate); + expect(element.controller('ngModel').$viewValue).toEqual(dateObj); }); }); @@ -544,14 +555,16 @@ describe('uiDateFormat', function() { var aDate = new Date(2012, 9, 11); var aDateTimestamp = aDate.getTime(); - var element = $compile('')($rootScope); + var element = $compile('')($rootScope); $rootScope.x = aDateTimestamp; $rootScope.$digest(); // Check that the model has not been altered expect($rootScope.x).toEqual(aDateTimestamp); // Check that the viewValue has been parsed correctly - expect(element.controller('ngModel').$viewValue).toEqual(aDate); + var dateFormat = element.datepicker('option', 'dateFormat'); + var dateObj = $.datepicker.formatDate(dateFormat, aDate); + expect(element.controller('ngModel').$viewValue).toEqual(dateObj); }); }); }); @@ -565,7 +578,7 @@ describe('uiDateFormat', function() { it('use ISO if not config value', function() { inject(['$compile', '$rootScope', function($compile, $rootScope) { - element = $compile('')($rootScope); + element = $compile('')($rootScope); scope = $rootScope; }]); @@ -573,31 +586,36 @@ describe('uiDateFormat', function() { var aISODateString = aDate.toISOString(); scope.x = aISODateString; scope.$digest(); - expect(element.controller('ngModel').$viewValue).toEqual(aDate); - }); - - it('use format value if config given', function() { - var format = 'yy DD, d MM'; - module(function($provide) { - $provide.constant('uiDateFormatConfig', format); - }); - - inject(['$compile', '$rootScope', function($compile, $rootScope) { - element = $compile('')($rootScope); - scope = $rootScope; - }]); - - var aDateString = '2012 Friday, 12 October'; - var expectedDate = new Date('2012-10-12'); - - scope.x = aDateString; - scope.$digest(); - var pickerDate = element.controller('ngModel').$viewValue; - expect(pickerDate.getDate()).toEqual(expectedDate.getUTCDate()); - expect(pickerDate.getUTCMonth()).toEqual(expectedDate.getUTCMonth()); - expect(pickerDate.getUTCFullYear()).toEqual(expectedDate.getUTCFullYear()); + var dateFormat = element.datepicker('option', 'dateFormat'); + var dateObj = $.datepicker.formatDate(dateFormat, aDate); + expect(element.controller('ngModel').$viewValue).toEqual(dateObj); }); + + //Logic change - no more uiDateFormatConfig constant used, we could set default $.datepicker globally or change + // it by providing options explicitly + // it('use format value if config given', function() { + // var format = 'yy DD, d MM'; + // module(function($provide) { + // $provide.constant('uiDateFormatConfig', format); + // }); + // + // inject(['$compile', '$rootScope', function($compile, $rootScope) { + // element = $compile('')($rootScope); + // scope = $rootScope; + // }]); + // + // var aDateString = '2012 Friday, 12 October'; + // var expectedDate = new Date('2012-10-12'); + // + // scope.x = aDateString; + // scope.$digest(); + // + // var pickerDate = element.controller('ngModel').$viewValue; + // expect(pickerDate.getDate()).toEqual(expectedDate.getUTCDate()); + // expect(pickerDate.getUTCMonth()).toEqual(expectedDate.getUTCMonth()); + // expect(pickerDate.getUTCFullYear()).toEqual(expectedDate.getUTCFullYear()); + // }); }); }); From d051e981c71e2bdcf9f45772fa52ebe481909885 Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Mon, 4 Apr 2016 16:59:18 +0300 Subject: [PATCH 5/6] minor fix, remove tmp code --- demo/index.html | 44 ++++++++++++++++---------------------------- demo/script.js | 21 ++++++++++----------- src/date.js | 3 ++- 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/demo/index.html b/demo/index.html index 37b294d..2962af9 100644 --- a/demo/index.html +++ b/demo/index.html @@ -16,40 +16,28 @@

Examples

ui-date (binding options)

- - + + - - - - +
{{ aDate }}
+
+ Read only +
- - - - - - +
+ Required date: +
+ The required date field is required. +
+
-

ui-date (binding options)

-
-
{{myForm.smth2.$error | json}}
-
{{myForm.smth2.$modelValue | json}}
- - - - - - -
{{ aDate1 }}
-
- - {{getDate(aDate1)}} -
-
+ + + + diff --git a/demo/script.js b/demo/script.js index 1560fac..c36312b 100644 --- a/demo/script.js +++ b/demo/script.js @@ -1,14 +1,13 @@ angular.module('MyApp', ['ui.date']) - .controller('MyCtrl', function ($scope) { - $scope.aDate = '2015-10-31'; - // $scope.aDate1 = 'Thursday, 11 October, 2012'; - $scope.aDate1 = '2015-10-31'; - // $scope.aDate1 = "2014-08-20T00:00:00-04:00"; - // $scope.aDate1 = "2016-12-28T15:58:21.162000Z"; + .controller('MyCtrl', function ($scope, $filter, $compile, $rootScope) { + // $scope.aDate = ; + // $scope.otherDate = 'Thursday, 11 October, 2012'; + // $scope.otherDate = '2015-10-31'; + // $scope.otherDate = $filter('date')((new Date("2014-08-20T00:00:00-04:00")).getTime(),'dd/MM/yyyy'); + // $scope.otherDate = "2016-12-28T15:58:21.162000Z"; $scope.dateOptions = { dateFormat: 'dd.mm.yy', - } - $scope.getDate = function(date) { - return typeof date; - } - }) \ No newline at end of file + }; + + + }); \ No newline at end of file diff --git a/src/date.js b/src/date.js index ac98921..c741f41 100644 --- a/src/date.js +++ b/src/date.js @@ -196,7 +196,7 @@ export default angular.module('ui.date', []) }); element.off('blur.datepicker').on('blur.datepicker', function() { - if (!showing) { + if (!showing && validateDate(dateFormat, ngModelCtrl.$viewValue)) { scope.$apply(function() { element.datepicker('setDate', element.datepicker('getDate')); ngModelCtrl.$render(); @@ -227,6 +227,7 @@ export default angular.module('ui.date', []) if (modelDateFormat) { validatedDate = validateDate(dateFormat, viewValue); + console.log('validatedDate',validatedDate); //here we going to format our value with modelDateFormat return validatedDate ? $.datepicker.formatDate(modelDateFormat, new Date(validatedDate)) : validatedDate; } From 5d66d9dbc4e6424b8d661f5f6712ede8e656e4dd Mon Sep 17 00:00:00 2001 From: Ivan Zaharchuk Date: Mon, 4 Apr 2016 17:14:18 +0300 Subject: [PATCH 6/6] fix npm jquery-ui version dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d11f78..ea61b37 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "expose-loader": "0.7.1", "jasmine-core": "^2.4.1", "jquery": "2.1.4", - "jquery-ui": "^1.11.4", + "jquery-ui": "^1.10.5", "karma": "^0.13.15", "karma-chrome-launcher": "^0.2.2", "karma-firefox-launcher": "^0.1.7",