问题
something similar may have been answered (ng-pattern + ng-change) but all responses were unable to fix this issue.
I have two imbricated directives for creating a form input, a parent directive to control name, label, validator etc. and a child directive to set pattern and input type specific stuff.
However, when setting a pattern, the value on my model is set to undefined when ng-pattern return false.
Directives:
<input-wrapper ng-model="vm.customer.phone" name="phone" label="Phone number">
<input-text type="tel"></input-text>
</input-wrapper>
Generated HTML:
<label for="phone">Phone number:</label>
<input type="text" name="phone"
ng-model="value"
ng-model-options="{ updateOn: \'blur\' }"
ng-change="onChange()"
ng-pattern="/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/">
JS:
angular.module('components', [])
.directive('inputWrapper', function() {
return {
restrict: 'E',
require: 'ngModel',
scope: true,
link: function (scope, element, attrs, ngModel) {
scope.name = attrs.name;
scope.label = attrs.label;
scope.onChange = function () {
ngModel.$setViewValue(scope.value);
};
ngModel.$render = function () {
scope.value = ngModel.$modelValue;
};
}
}
})
.directive('inputText', function() {
return {
restrict: 'E',
template: '<label for="{{name}}">{{label}}:</label><input type="text" name="{{name}}" ng-model="value" ng-model-options="{ updateOn: \'blur\' }" ng-change="onChange()" ng-pattern="pattern">',
link: function (scope, element, attrs) {
if (attrs.type === 'tel') {
scope.pattern = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
}
}
}
});
angular.module('app',['components'])
.controller('ctrl',function($scope){
var vm = this;
vm.customer = {
phone: '010203040506'
};
});
What am I doing wrong ?
Codepen for use case: https://codepen.io/Yosky/pen/yVrmvw
回答1:
By default in angular if a validator fail, undefined value assigned to ng-model, You can change this setting as follow :
<div ng-model-options="{ allowInvalid: true}">
read here for detail docs
回答2:
I had some requirements that meant that I really really didn't want ng-model to write out undefined to the scope when validation was invalid, and I didn't want the invalid value either, so allowInvalid didn't help. In stead I just wanted ng-model do not write anything, but I couldn't find any option for this.
So I couldn't see any way forward except for doing some monkey patching of the ng-model controller.
So first I required ngModel in the component I was building require: { model: 'ngModel' }
and then I did this in the $onInit hook:
const writeModelToScope = this.model.$$writeModelToScope;
const _this = this;
this.model.$$writeModelToScope = function() {
const allowInvalid = _this.model.$options.getOption('allowInvalid');
if (!allowInvalid && _this.model.$invalid) {
return;
}
writeModelToScope.bind(this)();
};
I also didn't want to take in a new model value while the value was invalid and the component had focus, so I did:
const setModelValue = this.model.$$setModelValue;
this.model.$$setModelValue = function(modelValue) {
_this.lastModelValue = modelValue;
if (_this.model.$invalid) {
return;
}
if (_this.hasFocus) {
return;
}
setModelValue.bind(this)(modelValue);
};
element.on('focus', () => {
this.hasFocus = true;
});
element.on('blur', (event) => {
this.hasFocus = false;
const allowInvalid = this.model.$options.getOption('allowInvalid');
if (!allowInvalid && this.model.$invalid) {
this.value = this.lastModelValue;
}
event.preventDefault();
});
Feel free to judge me, just know that I already feel dirty.
来源:https://stackoverflow.com/questions/41301290/angular-js-ngmodel-value-is-undefined-when-ng-pattern-is-set-in-directive