如何仅从内部修改指令范围属性

时间:2014-05-22 09:18:45

标签: javascript angularjs

我有一个自定义指令,需要另一个自定义指令作为父指令:

 .directive('controlErrorContainer', function () {
    return {
        restrict: 'E',
        templateUrl: 'template/common/control_error_container.html',
        require: '^controlContainer',
 ...
 });

control_error_container.html如下所示:

<div class="label label-danger" ng-show="isValid" ng-transclude>
</div>

所以最后,使用这些标签的html页面如下所示:

<control-container control-to-check="stuff">
    <input id="stuff" name="stuff" ng-model="stuff" />
    <control-error-container>
           You have failed me for the last time admiral!
    </control-error-container>
</control-container>

我想到的是控制容器存储对它应该保持的控件的引用,并且如果观察到的控制器有任何验证问题,则控制错误容器只显示其中的错误。

我有一个问题,即我希望controlErrorContainer在没有外部任何属性的情况下运行。正如您所看到的,它有一个带有&#34; isValid&#34;的ng-show标签。价值定义。这个值是不必要的,因为控件的有效性的值可以通过父自定义指令的容器获得(我这样做)。 这不起作用,我不知道如何使其工作,因为在创建控制器时,必须在某处定义它。如果我使用双向绑定创建一个范围,则angular会抛出异常。

所以问题是如何在不强迫用户创建不必要的属性的情况下完成这项工作?

1 个答案:

答案 0 :(得分:0)

据我了解,您正在尝试构建类似验证框架的东西。由于角度已经提供了一个,我建议尝试使用它。

Angular的validation framework建立在FormControllerNgModelController之上,它们在formngModel指令中缺少协作控制器。

添加自定义验证器只是编写一个指令,将验证函数挂钩到框架中。这种验证器的一个例子是:

app.directive('validUserType', function() {
    return {
      restrict: 'A',
      require: '?ngModel',
      link: function(scope, elem, attrs, ngModelCtrl) {
        var allowAdmin = attrs.allowAdmin && attrs.allowAdmin === 'true';

        if (ngModelCtrl) {
          ngModelCtrl.$parsers.push(userTypeValidator);
          ngModelCtrl.$formatters.push(userTypeValidator);
        }

        function userTypeValidator(value) {
          if (!value || value === 'guest' || (allowAdmin && value === 'admin')) {
            ngModelCtrl.$setValidity('validUserType', true);
            return value;
          } else {
            ngModelCtrl.$setValidity('validUserType', false);
            return;
          }
        }
      }
    };
});

您申请的是:

<input name="input" ng-model="userType" required valid-user-type allow-admin="true">

请注意,您可以拥有任意数量的验证器(required也是由角度提供的验证器),它们与具有其他属性(allow-admin="true")的普通指令没有区别。使其成为验证者的是它与ngModel集成的方式。您在用户提供输入时添加“解析器”,并在javascript代码更改值时添加格式化程序。除了验证之外,它还可以充当转换器,即转换字符串 - &gt; object(在解析器中),反之亦然(在formatter中)。在这种情况下,您需要2个独立的功能,而不是常见功能。

Angular的框架负责所有其他工作。它在输入/特定验证器/表单级别保持有效“标志”,可用于显示/隐藏验证消息或启用/禁用按钮。它还维护CSS类,可用于添加可视糖和“脏”标志,以通知用户哪些字段已被编辑。更重要的是,它只允许有效值(或undefined)传播到您的模型,这意味着如果您的控制器中有这样的内容:

$scope.$watch('userType', function(userType) {
    if (userType) {
        // make ajax with userType
    }
});

保证只有有效的userType值才会发送到服务器。

底线:它已经提供了很多,并且是正式维护的,所以在它之上构建它是有意义的。

查看此plunker(从角度文档中提取出来的弹药)。

当然,您可以使用control-containercontrol-error-container构建自己的验证框架。您的示例缺少的是实际验证器将如何挂钩到游戏中。我的偏好是将它应用于输入元素,就像应用角度验证器一样:

<control-container>
  <input ng-model="userType" valid-user-type allow-admin="true"/>
  <control-error-container>
    You have failed me for the last time admiral!
  </control-error-container>
</control-container>

valid-user-type是您的自定义验证程序,可将结果传递给control-container,然后从control-container传递到control-error-container。这三个指令类似于:

app.directive('controlContainer', function() {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    controller: function() {
      var controlErrorContainer = null;

      this.setValid = function(value) {
        if (controlErrorContainer) controlErrorContainer.setValid(value);
      }

      this.setControlErrorContainer = function(cec) {
        controlErrorContainer = cec;
      }
    },
    templateUrl: 'controlContainer.html'
  };
});

app.directive('controlErrorContainer', function() {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    require: ['controlErrorContainer', '^controlContainer'],
    templateUrl: 'controlErrorContainer.html',
    controller: ['$scope', function($scope) {
      $scope.isValid = true;
      this.setValid = function(value) {
        $scope.isValid = value;
      };
    }],
    link: function(scope, elem, attrs, controllers) {
      var controlErrorContainer = controllers[0];
      var controlContainer = controllers[1];
      controlContainer.setControlErrorContainer(controlErrorContainer);
    }
  };
});

app.directive('validUserType', function() {
  return {
    restrict: 'A',
    require: ['ngModel', '^controlContainer'],
    link: function(scope, elem, attrs, controllers) {
      var allowAdmin = attrs.allowAdmin && attrs.allowAdmin === 'true';

      var ngModel = controllers[0];
      var controlContainer = controllers[1];

      scope.$watch(
        function() {
          return ngModel.$viewValue;
        },
        function(value) {
          if (!value || value === 'guest' || (allowAdmin && value === 'admin')) {
            controlContainer.setValid(true);
          } else {
            controlContainer.setValid(false);
          }
        }
      );
    }
  };
});

可以<control-container control-to-check="stuff">这样的事情,但我认为更难以找到“东西”及其价值并在其上运行验证器(我不知道你是怎么做的)它是定义的。

查看完整的plunker