Angularjs 如何正确应用范围,以便顺序无关紧要
我正在尝试为一个指令编写一个单元测试,该指令将一个值与其他输入字段相匹配。问题是,如果我在应用指令的元素之前定义要匹配的元素,它就可以正常工作,否则就会失败 当模板为Angularjs 如何正确应用范围,以便顺序无关紧要,angularjs,unit-testing,jasmine,Angularjs,Unit Testing,Jasmine,我正在尝试为一个指令编写一个单元测试,该指令将一个值与其他输入字段相匹配。问题是,如果我在应用指令的元素之前定义要匹配的元素,它就可以正常工作,否则就会失败 当模板为 tpl = '<input name="verifyNewPassword" ng-model="verifyNewPassword" type="password"/>'; tpl += '<input name="newPassword" ng-model="newPassword" type="passwo
tpl = '<input name="verifyNewPassword" ng-model="verifyNewPassword" type="password"/>';
tpl += '<input name="newPassword" ng-model="newPassword" type="password" equals-to="userForm.verifyNewPassword"/>';
tpl = '<input name="newPassword" ng-model="newPassword" type="password" equals-to="userForm.verifyNewPassword"/>';
tpl+='<input name="verifyNewPassword" ng-model="verifyNewPassword" type="password"/>';
以下是我的测试代码:
describe('Unit: Testing Directives', function() {
var elm, scope;
beforeEach(function() {
module('mctApp');
inject(function($rootScope, $compile) {
scope = $rootScope.$new();
});
});
function compileDirective(tpl) {
if(!tpl) {
tpl = '<input name="newPassword" ng-model="newPassword" type="password" equals-to="userForm.verifyNewPassword"/>';
tpl += '<input name="verifyNewPassword" ng-model="verifyNewPassword" type="password"/>';
}
tpl = '<form name="userForm">' + tpl + '</form>';
inject(function($compile) {
var form = $compile(tpl)(scope);
});
scope.$digest();
}
it('must be valid form as both values are equal', function() {
scope.newPassword = 'abcdef';
scope.verifyNewPassword = 'abcdef';
compileDirective();
expect(scope.userForm.$valid).toBeTruthy();
});
});
description('单元:测试指令',函数()){
var-elm,范围;
beforeach(函数(){
模块(“mctApp”);
注入(函数($rootScope,$compile){
scope=$rootScope.$new();
});
});
函数compileDirective(tpl){
如果(!tpl){
第三方物流='';
第三方物流+=”;
}
tpl=''+tpl+'';
注入(函数($compile){
变量形式=$compile(tpl)(范围);
});
范围。$digest();
}
它('必须是有效形式,因为两个值相等',函数(){
scope.newPassword='abcdef';
scope.verifyNewPassword='abcdef';
compileDirective();
expect(scope.userForm.$valid).toBeTruthy();
});
});
测试失败,因为当监视开始启动时,的$viewValue
等于ngModelController,因此字段有效性设置为false,表单无效
当您在输入ngModel
分配给的范围内观察对象时(该范围已设置为“abcdef”),手表只被调用一次。相反,如果您查看要比较的输入的ngModel.$viewValue
,它保证初始状态始终正确,而不管DOM中输入的顺序如何
我还认为,观察这个值更有意义,因为它是你正在比较的值
.directive('equalsTo', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
var sc = scope;
scope.$watch(attrs.equalsTo + '.$viewValue', function() {
var eqCtrl = scope.$eval(attrs.equalsTo);
console.log('Value1: ' + ctrl.$viewValue + ', Value2: ' + eqCtrl.$viewValue);
if (ctrl.$viewValue===eqCtrl.$viewValue || (!!!ctrl.$viewValue && !!!eqCtrl.$viewValue)) {
ctrl.$setValidity('equalsTo', true);
eqCtrl.$setValidity('equalsTo', true);
} else {
ctrl.$setValidity('equalsTo', false);
eqCtrl.$setValidity('equalsTo', false);
}
});
}
};
})
注意
如果您使用的是angular 1.3+,那么值得一看新的验证器管道,因为它是解决相同问题的更优雅的方法。首先,对于您的模型场景,有一个比同步验证两个输入更好的UX解决方案。第一个字段(密码)应仅根据您的密码格式限制进行验证,并且仅应检查第二个字段(密码确认)是否与密码相等。这有助于用户在选择有效和可重新键入的密码时保持理智。(换句话说,密码确认是第二次输入的唯一领域。如果你把确认搞砸了,它不会突然使之前有效的输入失效。)
(如果使用AngularJS版本<1.3
,则使用$parsers
和$setValidity
而不是$validator
)
测试指令将是轻而易举的事,因为您只需要调整模型
作为旁注,即使您决定要同时验证两个输入,也最好根据相应的模型值验证每个输入(对两个输入使用myequalTo
指令),而不是强制兄弟控制器之间进行直接通信。我认为在应用范围时需要使用$超时处理$digest进程,因为一旦完成$digest,它就会应用作用域
这就是我过去应用范围的方式
$timeout(function(){
$scope.$apply()
}
在测试中,可以使用$timeout.flush()同步刷新延迟函数队列
<input type="password" ng-model="password" required ng-pattern="/^(?=.*\w)(?=.*\W)/">
<input type="password" ng-model="passwordConfirmation" equal-to="password">
.directive('equalTo', ['$parse', function ($parse) {
return {
require: 'ngModel',
compile: function (element, attrs) {
var getOtherValue = $parse(attrs.equalTo);
return function link ($scope, $element, $attrs, ngModelCtrl) {
ngModelCtrl.$validators.equalTo = function (value) {
return (value === getOtherValue($scope));
};
};
}
};
}])
$timeout(function(){
$scope.$apply()
}