我试图弄清楚为什么当用户首先在电话号码字段中输入值然后清除时,我的两个错误消息(“这是必填字段”和“电话号码必须为10位数字”)重叠的原因他们(即空白)。
在这种空白情况下,仅应出现“这是必填字段”消息。
这是我正在使用的代码:
HTML:
<div ng-class="$ctrl.inline ? 'form-inline' : 'form-group'">
<label ng-if="$ctrl.label">{{$ctrl.label}}<span style="color:red;" ng-if="$ctrl.isRequired">*</span></label>
<div ng-class="$ctrl.inline ? 'd-inline-block' : ''">
<span class="color-black">(</span>
<input type="text" name="{{$ctrl.phone[0].name}}" class="form-control" ng-model="$ctrl.phone[0].num" ng-required="$ctrl.isRequired"
ng-minlength="3" ng-model-options="$ctrl.modelOpts" ng-keydown="$ctrl.maxlength($event, 3, 0)" ng-disabled="$ctrl.isDisabled">
<span class="color-black">)</span>
<input type="text" name="{{$ctrl.phone[1].name}}" class="form-control" ng-model="$ctrl.phone[1].num" ng-required="$ctrl.isRequired" ng-disabled="$ctrl.isDisabled"
ng-minlength="3" ng-model-options="$ctrl.modelOpts" ng-keydown="$ctrl.maxlength($event, 3, 1)">
<span class="color-black">-</span>
<input type="text" name="{{$ctrl.phone[2].name}}" class="form-control" ng-model="$ctrl.phone[2].num" ng-required="$ctrl.isRequired" ng-disabled="$ctrl.isDisabled"
ng-minlength="4" ng-model-options="$ctrl.modelOpts" ng-keydown="$ctrl.maxlength($event, 4, 2)">
</div>
<div ng-if="$ctrl.validateRequired()" class="error-label">
<div class="text-danger">This is a required field.</div>
</div>
<div ng-messages="$ctrl.form.$submitted && $ctrl.form[$ctrl.name].$error" class="error-label">
<div class="text-danger" ng-message="sameNum">Your <span style="text-transform: lowercase">{{$ctrl.label}}</span> cannot be the same as your cell number.</div>
<div class="text-danger" ng-message="phoneLength">Phone number must be 10 digits.</div>
</div>
</div>
上面的HTML代码附带Java脚本代码:
(function(angular) {
'use strict';
angular.module('rvComponents')
.component('rvPhoneInput', {
bindings: {
compare: '=?',
form: '<',
inline: '<?',
isRequired: '<?',
label: '@?',
name: '@',
nextElem: '@?',
value: '=',
isDisabled: '<?'
},
controller: PhoneInputController,
require: {
modelCtrl: 'ngModel',
modelOptsCtrl: 'ngModelOptions'
},
templateUrl: './components/rvPhoneInput/rvPhoneInput.html'
});
function PhoneInputController($element, $scope, $window) {
var ctrl = this;
ctrl.phone = [
{
name: ctrl.name + 1,
num: ''
},
{
name: ctrl.name + 2,
num: ''
},
{
name: ctrl.name + 3,
num: ''
}
];
ctrl.modelOpts = {
allowInvalid: true
};
$element.attr('ng-model-options', JSON.stringify(ctrl.modelOpts));
$scope.$watch('$ctrl.value', function(newVal) {
if (newVal) {
if (newVal.length === 10) {
ctrl.phone[0].num = newVal.substring(0, 3);
ctrl.phone[1].num = newVal.substring(3, 6);
ctrl.phone[2].num = newVal.substring(6, 10);
}
} else {
ctrl.phone[0].num = ctrl.phone[1].num = ctrl.phone[2].num = '';
}
});
$scope.$watchGroup(['$ctrl.phone[0].num', '$ctrl.phone[1].num', '$ctrl.phone[2].num'], function(newVals) {
var newPhoneNum = (newVals[0] || '') + (newVals[1] || '') + (newVals[2] || '');
if (newPhoneNum) {
if (ctrl.value !== newPhoneNum) {
ctrl.value = newPhoneNum;
ctrl.modelCtrl && ctrl.modelCtrl.$setViewValue(newPhoneNum);
}
} else {
ctrl.value = undefined;
}
});
ctrl.$onInit = function() {
if (ctrl.modelCtrl) {
ctrl.modelCtrl.$validators.sameNum = function(modelVal) {
return !modelVal || !ctrl.compare || (modelVal && modelVal !== ctrl.compare);
};
ctrl.modelCtrl.$validators.phoneLength = function(modelVal) {
return !modelVal || (modelVal && modelVal.length === 10);
};
}
if (ctrl.modelOptsCtrl) {
angular.merge(ctrl.modelOptsCtrl.$options, ctrl.modelOpts);
}
};
$element.on('phoneFocus', function(evt) {
$element.find('input[name="'+ctrl.phone[0].name+'"]').focus();
});
ctrl.maxlength = maxlength;
ctrl.validateRequired = validateRequired;
function maxlength(e, max, pos) {
if (e.which === 9 || e.which === 13 || e.which === 16) {
return true;
}
var isBackspace = e.which === 8;
var isLeftArrow = e.which === 37;
var isRightArrow = e.which === 39;
if ((!isBackspace && !isLeftArrow && !isRightArrow && (e.which < 48 || e.which > 57)) || (e.shiftKey && (e.which >= 48 && e.which <= 57))) {
return e.preventDefault();
}
var inputLength = (ctrl.phone[pos].num || '').length;
if (inputLength === max - 1 || ((inputLength === 1 || !inputLength) && isBackspace)) {
var watcher = $scope.$watch(function() {
return (ctrl.phone[pos].num || '').length;
}, function(newVal) {
// focus to next element when input's pre-determined length is reached
if (newVal === (pos === 2 ? 4 : 3) || !newVal) {
var elem;
if (!newVal) {
elem = $element.find('input[name="'+ctrl.phone[pos === 0 ? pos : pos].name+'"]');
} else {
elem = (pos === 2) ? $(ctrl.nextElem) : $element.find('input[name="'+ctrl.phone[pos+1].name+'"]');
}
elem.focus();
// destroy watch
watcher();
}
});
} else if (inputLength >= max && !isBackspace && !isLeftArrow && !isRightArrow) {
e.preventDefault();
}
}
function validateRequired() {
return ctrl.form.$submitted && ctrl.phone.every(function(phone) {
return ctrl.form[phone.name].$error.required;
}) && !ctrl.isDisabled;
}
}
PhoneInputController.$inject = ['$element', '$scope', '$window'];
})(angular);