考虑以下示例:
<input type="text" ng-model="client.phoneNumber" phone-number>
<button ng-click="doSomething()">Do Something</button>
.directive("phoneNumber", function($compile) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
scope.mobileNumberIsValid = true;
var errorTemplate = "<span ng-show='!mobileNumberIsValid'>Error</span>";
element.after($compile(errorTemplate)(scope)).on('blur', function() {
scope.$apply(function() {
scope.mobileNumberIsValid = /^\d*$/.test(element.val());
});
});
}
};
});
查看demo,如果您在电话号码末尾添加“a”,然后点击按钮,则不会调用doSomething()
。如果再次单击该按钮,则会调用doSomething()
。
为什么第一次不调用doSomething()
?任何想法如何解决这个问题?
注意:保持验证模糊非常重要。
答案 0 :(得分:9)
mousedown
事件。blur
上,模糊回调触发以验证输入值。mouseup
事件。这就像点击一个按钮但移动到它之外,然后释放鼠标以取消按钮点击。这是ng-click
未触发的原因。因为按钮没有触发mouseup
事件。使用ng-pattern
动态验证输入值,并根据ngModel.$invalid
属性立即显示/隐藏错误范围。
根据作者的要求,用另一种解决方案更新答案。
HTML
<body ng-app="Demo" ng-controller="DemoCtrl as demoCtrl">
<pre>{{ client | json }}</pre>
<div id="wrapper">
<input type="text" phone-number
ng-model="client.phoneNumber"
ng-blur="demoCtrl.validateInput(client.phoneNumber)">
</div>
<button ng-mousedown="demoCtrl.pauseValidation()"
ng-mouseup="demoCtrl.resumeValidation()"
ng-click="doSomething()">Do Something</button>
</body>
我在输入上使用了ng-blur
指令来触发验证。如果在ng-mousedown
之前触发ng-blur
,ng-blur
回调将推迟到ng-mouseup
被触发。这是通过利用$q
服务来实现的。
答案 1 :(得分:4)
这是因为该指令正在将<span>Error</span>
插入当前按钮所在的位置,从而干扰了click事件的位置。你可以通过移动文本框上方的按钮来看到这一点,一切都应该正常。
编辑:
如果您确实必须将错误放在同一位置,并在不创建自己的点击指令的情况下解决问题,则可以使用ng-mousedown
代替ng-click
。这将在处理模糊事件之前触发点击代码。
答案 2 :(得分:4)
此处:http://jsbin.com/epEBECAy/25/edit
正如其他答案所解释的那样,在按钮上的onmouseup事件发生之前,按钮的外观会移动按钮,从而导致您遇到的问题。实现所需内容的最简单方法是对表单进行样式设置,使得跨度的外观不会导致按钮移动(从UX的角度来看,这是一个好主意)。您可以通过将input
元素包装在div
样式为white-space:nowrap
的情况下执行此操作。只要跨度有足够的水平空间,按钮就不会移动,ng-click事件将按预期工作。
<div id="wrapper">
<div style='white-space:nowrap;'>
<input type="text" ng-model="client.phoneNumber" phone-number>
</div>
<button ng-click="doSomething()">Do Something</button>
</div>
答案 3 :(得分:1)
不是直接答案,而是以不同方式编写指令的建议(html是相同的):
angular.module("Demo", [])
.controller("DemoCtrl", function($scope) {
$scope.client = {
phoneNumber: '0451785986'
};
$scope.doSomething = function() {
console.log('Doing...');
};
})
.directive("phoneNumber", function($compile) {
var errorTemplate = "<span ng-show='!mobileNumberIsValid'> Error </span>";
var link = function(scope, element, attrs) {
$compile(element.find("span"))(scope);
scope.mobileNumberIsValid = true;
scope.$watch('ngModel', function(v){
scope.mobileNumberIsValid = /^\d*$/.test(v);
});
};
var compile = function(element, attrs){
var h = element[0].outerHTML;
var newHtml = [
'<div>',
h.replace('phone-number', ''),
errorTemplate,
'</div>'
].join("\n");
element.replaceWith(newHtml);
return link;
};
return {
scope: {
ngModel: '='
},
compile: compile
};
});
答案 4 :(得分:0)
我建议在验证电话号码时使用$parsers
和$setValidity
方式。
app.directive('phoneNumber', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ctrl) {
if (!ctrl) return;
ctrl.$parsers.unshift(function(viewValue) {
var valid = /^\d*$/.test(viewValue);
ctrl.$setValidity('phoneNumber', valid);
return viewValue;
});
ctrl.$formatters.unshift(function(modelValue) {
var valid = /^\d*$/.test(modelValue);
ctrl.$setValidity('phoneNumber', valid);
return modelValue;
});
}
}
});
因此,您可以在视图中的字段上使用$valid
属性:
<form name="form" ng-submit="doSomething()" novalidate>
<input type="text" name="phone" ng-model="phoneNumber" phone-number/>
<p ng-show="form.phone.$invalid">(Show on error)Wrong phone number</p>
</form>
如果您只想在blur
上显示错误,可以使用(在此处找到:AngularJS Forms - Validate Fields After User Has Left Field):
var focusDirective = function () {
return {
restrict: 'E',
require: '?ngModel',
link: function (scope, element, attrs, ctrl) {
var elm = $(element);
if (!ctrl) return;
elm.on('focus', function () {
elm.addClass('has-focus');
ctrl.$hasFocus = true;
if(!scope.$$phase) scope.$digest();
});
elm.on('blur', function () {
elm.removeClass('has-focus');
elm.addClass('has-visited');
ctrl.$hasFocus = false;
ctrl.$hasVisited = true;
if(!scope.$$phase) scope.$digest();
});
elm.closest('form').on('submit', function () {
elm.addClass('has-visited');
ctrl.$hasFocus = false;
ctrl.$hasVisited = true;
if(!scope.$$phase) scope.$digest();
})
}
}
};
app.directive('input', focusDirective);
因此,如果字段现在是焦点,那么您将拥有hasFocus
属性;如果该字段被模糊了一次或多次,您将拥有hasVisited
属性:
<form name="form" ng-submit="doSomething()" novalidate>
<input type="text" name="phone" ng-model="phoneNumber" phone-number/>
<p ng-show="form.phone.$invalid">[error] Wrong phone number</p>
<p ng-show="form.phone.$invalid
&& form.phone.$hasVisited">[error && visited] Wrong phone number</p>
<p ng-show="form.phone.$invalid
&& !form.phone.$hasFocus">[error && blur] Wrong phone number</p>
<div><input type="submit" value="Submit"/></div>
</form>
答案 5 :(得分:0)
我用以下内容修复了它。
<button class="submitButton form-control" type="submit" ng-mousedown="this.form.submit();" >