From bcce78a42e35b6e8ee881dc49686affdabd405d1 Mon Sep 17 00:00:00 2001 From: mohamed amr Date: Tue, 24 Nov 2015 23:19:08 +0200 Subject: [PATCH 1/4] fix(ngRequired): set valid to false if select value is required (value is not in options) --- src/ng/directive/ngOptions.js | 41 ++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index 8032253573e9..6676461b4007 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -510,11 +510,6 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { } else { - ngModelCtrl.$isEmpty = function(value) { - return !value || value.length === 0; - }; - - selectCtrl.writeValue = function writeNgOptionsMultiple(value) { options.items.forEach(function(option) { option.element.selected = false; @@ -558,6 +553,42 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { } } + function isViewOptionValid(viewValue) { + + var isValidOption = false; + var viewOptions = []; + // Get all option and add them to viewOptions array + angular.forEach(options.items, function(item) { + viewOptions.push(options.getViewValueFromOption(item)); + }); + + // In case of multiple view is an array so validate all view values + // if one of them match set isValidOption to true + if (multiple) { + for (var i = 0, length = viewValue.length; i < length; i++) { + if (viewOptions.indexOf(viewValue[i]) > -1) { + isValidOption = true; + break; + } + } + } else { + if (viewOptions.indexOf(viewValue) > -1) { + isValidOption = true; + } + } + + return isValidOption; + } + + // Copy the implementation of $isEmpty function to be used in overwritten one + var $$isEmpty = ngModelCtrl.$isEmpty; + + ngModelCtrl.$isEmpty = function(value) { + if ($$isEmpty(value)) { + return true; + } + return !isViewOptionValid(value); + }; if (providedEmptyOption) { From b1946fd4fe4a6b010ef402f1048a64f7eed574fa Mon Sep 17 00:00:00 2001 From: mohamed amr Date: Fri, 27 Nov 2015 22:46:56 +0200 Subject: [PATCH 2/4] fix(ngRequired): set isOptionvalid flag during writting the value --- src/ng/directive/ngOptions.js | 47 +++++++++-------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index 8e950ddc1188..fc225c6c2816 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -414,6 +414,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { var selectCtrl = ctrls[0]; var ngModelCtrl = ctrls[1]; var multiple = attr.multiple; + var isOptionValid = true; // The emptyOption allows the application developer to provide their own custom "empty" // option when the viewValue does not match any of the option values. @@ -466,7 +467,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { selectCtrl.writeValue = function writeNgOptionsValue(value) { var option = options.getOptionFromViewValue(value); - + isOptionValid = option ? true : false; if (option && !option.disabled) { if (selectElement[0].value !== option.selectValue) { removeUnknownOption(); @@ -516,10 +517,16 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { }); if (value) { + var matchedOptions = 0; value.forEach(function(item) { var option = options.getOptionFromViewValue(item); - if (option && !option.disabled) option.element.selected = true; + if (option && !option.disabled) { + ++matchedOptions; + option.element.selected = true; + } }); + + isOptionValid = (matchedOptions > 0) ? true : false; } }; @@ -553,41 +560,11 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { } } - function isViewOptionValid(viewValue) { - - var isValidOption = false; - var viewOptions = []; - // Get all option and add them to viewOptions array - angular.forEach(options.items, function(item) { - viewOptions.push(options.getViewValueFromOption(item)); - }); - - // In case of multiple view is an array so validate all view values - // if one of them match set isValidOption to true - if (multiple) { - for (var i = 0, length = viewValue.length; i < length; i++) { - if (viewOptions.indexOf(viewValue[i]) > -1) { - isValidOption = true; - break; - } - } - } else { - if (viewOptions.indexOf(viewValue) > -1) { - isValidOption = true; - } - } - - return isValidOption; - } - - // Copy the implementation of $isEmpty function to be used in overwritten one + // Copy the implementation of $isEmpty function to be used in overwritten one. var $$isEmpty = ngModelCtrl.$isEmpty; ngModelCtrl.$isEmpty = function(value) { - if ($$isEmpty(value)) { - return true; - } - return !isViewOptionValid(value); + return $$isEmpty(value) || !isOptionValid; }; if (providedEmptyOption) { @@ -762,7 +739,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { ngModelCtrl.$render(); // Check to see if the value has changed due to the update to the options - if (!ngModelCtrl.$isEmpty(previousValue)) { + if (!$$isEmpty(previousValue)) { var nextValue = selectCtrl.readValue(); var isNotPrimitive = ngOptions.trackBy || multiple; if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) { From 08aad22dbaa77af9497eb57216e8c8273b43101a Mon Sep 17 00:00:00 2001 From: mohamed amr Date: Wed, 2 Dec 2015 23:22:43 +0200 Subject: [PATCH 3/4] revert: set isOptionvalid flag during writting the value (to try another impllementation ) --- src/ng/directive/ngOptions.js | 47 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index fc225c6c2816..8e950ddc1188 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -414,7 +414,6 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { var selectCtrl = ctrls[0]; var ngModelCtrl = ctrls[1]; var multiple = attr.multiple; - var isOptionValid = true; // The emptyOption allows the application developer to provide their own custom "empty" // option when the viewValue does not match any of the option values. @@ -467,7 +466,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { selectCtrl.writeValue = function writeNgOptionsValue(value) { var option = options.getOptionFromViewValue(value); - isOptionValid = option ? true : false; + if (option && !option.disabled) { if (selectElement[0].value !== option.selectValue) { removeUnknownOption(); @@ -517,16 +516,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { }); if (value) { - var matchedOptions = 0; value.forEach(function(item) { var option = options.getOptionFromViewValue(item); - if (option && !option.disabled) { - ++matchedOptions; - option.element.selected = true; - } + if (option && !option.disabled) option.element.selected = true; }); - - isOptionValid = (matchedOptions > 0) ? true : false; } }; @@ -560,11 +553,41 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { } } - // Copy the implementation of $isEmpty function to be used in overwritten one. + function isViewOptionValid(viewValue) { + + var isValidOption = false; + var viewOptions = []; + // Get all option and add them to viewOptions array + angular.forEach(options.items, function(item) { + viewOptions.push(options.getViewValueFromOption(item)); + }); + + // In case of multiple view is an array so validate all view values + // if one of them match set isValidOption to true + if (multiple) { + for (var i = 0, length = viewValue.length; i < length; i++) { + if (viewOptions.indexOf(viewValue[i]) > -1) { + isValidOption = true; + break; + } + } + } else { + if (viewOptions.indexOf(viewValue) > -1) { + isValidOption = true; + } + } + + return isValidOption; + } + + // Copy the implementation of $isEmpty function to be used in overwritten one var $$isEmpty = ngModelCtrl.$isEmpty; ngModelCtrl.$isEmpty = function(value) { - return $$isEmpty(value) || !isOptionValid; + if ($$isEmpty(value)) { + return true; + } + return !isViewOptionValid(value); }; if (providedEmptyOption) { @@ -739,7 +762,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { ngModelCtrl.$render(); // Check to see if the value has changed due to the update to the options - if (!$$isEmpty(previousValue)) { + if (!ngModelCtrl.$isEmpty(previousValue)) { var nextValue = selectCtrl.readValue(); var isNotPrimitive = ngOptions.trackBy || multiple; if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) { From e48a6b053f2deb746fb058790b2c0c5ade32f113 Mon Sep 17 00:00:00 2001 From: mohamed amr Date: Thu, 3 Dec 2015 02:08:10 +0200 Subject: [PATCH 4/4] fix(ngRequired): set valid to false if select value is required (add isSelectedOptionValid function) --- src/ng/directive/ngOptions.js | 67 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index 8e950ddc1188..150eb2546543 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -387,6 +387,34 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { selectValueMap[selectValue] = optionItem; } + /** + * + * @returns {boolean} + */ + function isSelectedOptionValid() { + + var selectedValue = selectElement.val(); + + if (!selectedValue) { + return false; + } + + // in case select is multiple then check + // if one of the selected values matched with the options return true + // or return false if no value match + if (isArray(selectedValue)) { + for (var i = 0, length = selectedValue.length; i < length; i++) { + if (selectValueMap[selectedValue[i]]) { + return true; + } + } + return false; + } + + return !!selectValueMap[selectedValue]; + + } + return { items: optionItems, selectValueMap: selectValueMap, @@ -397,7 +425,9 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { // If the viewValue could be an object that may be mutated by the application, // we need to make a copy and not return the reference to the value on the option. return trackBy ? angular.copy(option.viewValue) : option.viewValue; - } + }, + + isSelectedOptionValid: isSelectedOptionValid }; } }; @@ -552,42 +582,11 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { } } - - function isViewOptionValid(viewValue) { - - var isValidOption = false; - var viewOptions = []; - // Get all option and add them to viewOptions array - angular.forEach(options.items, function(item) { - viewOptions.push(options.getViewValueFromOption(item)); - }); - - // In case of multiple view is an array so validate all view values - // if one of them match set isValidOption to true - if (multiple) { - for (var i = 0, length = viewValue.length; i < length; i++) { - if (viewOptions.indexOf(viewValue[i]) > -1) { - isValidOption = true; - break; - } - } - } else { - if (viewOptions.indexOf(viewValue) > -1) { - isValidOption = true; - } - } - - return isValidOption; - } - // Copy the implementation of $isEmpty function to be used in overwritten one var $$isEmpty = ngModelCtrl.$isEmpty; ngModelCtrl.$isEmpty = function(value) { - if ($$isEmpty(value)) { - return true; - } - return !isViewOptionValid(value); + return $$isEmpty(value) || !options.isSelectedOptionValid(); }; if (providedEmptyOption) { @@ -762,7 +761,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { ngModelCtrl.$render(); // Check to see if the value has changed due to the update to the options - if (!ngModelCtrl.$isEmpty(previousValue)) { + if (!$$isEmpty(previousValue)) { var nextValue = selectCtrl.readValue(); var isNotPrimitive = ngOptions.trackBy || multiple; if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {