我正在使用 AngularJS 的 v1.2.0 rc2 并且想知道为多个 Controller 提供通用功能的最佳方法是什么。
我想在编辑模型的所有 Controller 中使用以下验证函数:
$scope.canSave = function (formController) {
return formController.$dirty && formController.$valid;
};
$scope.validationClasses = function (modelController) {
return {
'has-error': modelController.$invalid && modelController.$dirty,
'has-success': modelController.$valid && modelController.$dirty
};
};
我想让我的 Controller 保持干燥,所以我定义了一个工厂,如下所示:
angular.module('myModule', [])
.factory('validationFactory', [function () {
return {
validationClasses: function (modelController) {
return {
'has-error': modelController.$invalid && modelController.$dirty,
'has-success': modelController.$valid && modelController.$dirty
};
},
isFormValid: function (formController) {
return formController.$dirty && formController.$valid;
}
};
}]);
最初,我只是将工厂混合到需要它的 Controller 中,如下所示:
$scope.canSave = validationFactory.isFormValid;
$scope.validationClasses = validationFactory.validationClasses;
但我意识到我可以将它们添加到模块运行方法中的 $rootScope 中,如下所示:
angular.module('myModule', [])
.run([
'$rootScope',
'validationFactory',
function ($rootScope, validationFactory) {
$rootScope.canSave = $rootScope.canUpdate = validationFactory.isFormValid;
$rootScope.validationClasses = validationFactory.validationClasses;
}]);
现在它们可以不加选择地在每个 Controller 中使用,并且需要做的接线更少。
View 模板中使用的函数如下:
<form name="questionForm" novalidate>
<div class="form-group" ng-class="validationClasses(questionForm.question)">
<label for="questionText" class="control-label">Text</label>
<input type="text" ng-model="question.text" name="question"
id="questionText" class="form-control" required/>
<span ng-show="questionForm.question.$error.required"
class="help-block">Question text is required</span>
</div>
...
<div class="form-group" ng-switch on="action">
<button type="button" ng-switch-when="New" ng-click="save()"
ng-disabled="!canSave(questionForm)"
class="btn btn-primary">Save</button>
<button type="button" ng-switch-default ng-click="update()"
ng-disabled="!canUpdate(questionForm)"
class="btn btn-primary">Update</button>
<button type="button" ng-click="cancel()"
class="btn btn-default">Cancel</button>
</div>
</form>
我的问题是:
更新的解决方案
我选择使用自定义指令,而不是向 $rootScope 添加函数,因为它有一股难闻的味道。
我创建了自定义属性
validation-class-for="<input.name>"
和 disabled-when-invalid
所以标记看起来像这样:<div class="form-group" validation-class-for="question">
<label for="questionText" class="control-label">Text</label>
<input type="text" ng-model="question.text" name="question"
id="questionText" class="form-control" required/>
<span ng-show="questionForm.question.$error.required"
class="help-block">Question text is required</span>
</div>
<button type="button" ng-click="save()" disabled-when-invalid
class="btn btn-primary">Save</button>
这些指令只需要一个表单祖先并观察一个函数来确定状态。
angular.module('myModule', [])
.directive('validationClassFor', function () {
return {
require: '^form',
link: function (scope, element, attributes, formController) {
scope.$watch(function () {
var field = formController[attributes.validationClassFor];
if (field.$invalid && field.$dirty) {
element.removeClass('has-success').addClass('has-error');
} else if (field.$valid && field.$dirty) {
element.removeClass('has-error').addClass('has-success');
} else {
element.removeClass('has-error').removeClass('has-success');
}
});
}
};
})
.directive('disabledWhenInvalid', function () {
return {
require: '^form',
link: function (scope, element, attributes, formController) {
scope.$watch(function () {
return formController.$dirty && formController.$valid;
}, function (value) {
element.prop('disabled', !value);
});
}
};
});
现在也不需要验证工厂。
最佳答案
我不建议使用共享逻辑的范围。这会降低可重用性并在您想要测试它时产生影响。
您可以使用类扩展:http://ejohn.org/blog/simple-javascript-inheritance/提取共同逻辑。
关于AngularJS 通用 Controller 功能 - 在需要的地方混合或在 $rootScope 上定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19381225/