AngularJS 通用 Controller 功能 - 在需要的地方混合或在 $rootScope 上定义?

标签 angularjs angularjs-controller

我正在使用 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 添加常用功能吗?如果是这样,有什么陷阱?
  • 仅在必要时混合通用功能会更好吗?
  • 有没有更好的方法来达到同样的结果?

  • 更新的解决方案

    我选择使用自定义指令,而不是向 $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/提取共同逻辑。
  • 您可以使用 Angular 消息来广播切换状态的事件,例如来自验证监听器的“有效”。
  • 您可以根据某些条件使用拦截器来阻止后端请求。
  • 关于AngularJS 通用 Controller 功能 - 在需要的地方混合或在 $rootScope 上定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19381225/

    相关文章:

    angularjs - 污染 $scope 对象会影响性能吗?

    angularJS 指令不会立即支持 ng-show/ng-hide

    javascript - 将 jquery Uniform 插件与 AngularJS 一起使用

    angularjs - 如何添加丢失的外键/实体?使用 JObjects 保存 BreezeJs

    javascript - AngularJS json 数据未显示在文本区域上

    javascript - Angular : Scope issue in $http success callback

    javascript - 适用于 android、ios 和 angularjs 的 Feed 阅读器

    c# - 在 Asp.net Web API 中处理 CORS 预检

    javascript - Angular.js 命名空间模块 Controller

    javascript - ng-click 没有在 angularjs 中触发?