使用 controllerAs 语法通过指令 $watch 更改父控制器模型

Change parent controller model through directive $watch using controllerAs syntax

我是 angular 的 controllerAs 语法的新手,只是想了解它如何与指令一起使用。我已经为密码验证创建了一个指令。我想根据条件使一些标志为真,这些标志将在父模板中用于显示错误消息。我不知道如何实现!

JSFiddle

VIEW

<div ng-app="myapp">
    <fieldset ng-controller="PersonCtrl as person">
        <input name="emailID" type="text" ng-model="person.first" >
        <input name="pass" type="password" ng-model="person.pass" password-validator>
        <p ng-show="person.showMsg">Password validation message here.</p>
    </fieldset>
</div>

指令

myapp.directive('passwordValidator',function() {
        return {
        controller : PasswordCtrl,
      controllerAs : 'dvm',
      bindToController : true,
      require : ['ngModel','passwordValidator'],
      link : function(scope,ele,attrs,ctrls) {
        var person = ctrls[1];
        var ngModelCtrl = ctrls[0];

        scope.$watch(function() {
                    return ngModelCtrl.$modelValue;
        },function(newVal) {
          if(newVal!='') {
            person.showMsg = true;
          } else {
            person.showMsg = false;
          }
          console.log(person.showMsg);
        });
      }
    }

    function PasswordCtrl() {

    }
});

Specially I want to understand why and how below watch is working fine!

// Why this below is also working, can anyone explain what's going behind!! 
scope.$watch('person.pass',function(newVal) {
    console.log("Watch fires");
});

这只是为了学习目的,所以请解释 controllerAsbindToController 是如何工作的!

你的例子有点乱,但我会尽量回答你的问题。

// Why this below is also working, can anyone explain what's going behind!! 
scope.$watch('person.pass',function(newVal) {
    console.log("Watch fires");
});

这是有效的,因为你的指令使用相同的范围和变量作为它的父控制器。

this.checkDirCtrl = function() {
    console.log($scope.dvm);
}

this 未定义,因为您在 SAME 范围内使用 controllerAs,因此未创建名为 dvm 的新变量,并且所有 dvm 控制器变量都在父范围内初始化。

这意味着你不需要 'inject' person controller 进入指令,因为你已经在指令范围内有控制器实例。因此,只需像这样设置您的变量 'showMsg',它就会像魔术一样工作!

      if(newVal!='') {
        scope.person.showMsg = true;
      } else {
        scope.person.showMsg = false;
      }
      console.log(scope.person.showMsg);

我给你做了一个fiddle:JSFiddle

我知道这不是你问题的一部分,我会解决的,但是使用指令 'ng-controller' 是一种反模式。如果有兴趣,为什么我可以单独解释 post 但简而言之,这会使代码更难理解。

现在,进入问题的核心。

通过阅读 bindToController 的 Angular 文档可以看出,如果您没有同时创建一个独立的作用域,即 scope: truescope: {} 它不会做任何东西。

就我个人而言,我以前从未使用过它,而且似乎不是特别有用。

使用 ng-controller 实质上是将 属性 添加到带有该控制器对象的当前范围。

所以:

<fieldset ng-controller="PersonCtrl as person">

实际上是在说,(以做作的方式):

$scope.person = new PersonCtrl();

你的指令 passwordValidator 在其中使用 controllerAs 语法基本上是在做:

$scope.dvm= new PasswordCtrl();

在这种情况下,您实际上拥有一个范围对象,如下所示:

$scope = {
    person = new PersonCtrl(),
    dvm: new PasswordCtrl()
}

您的 person 控制器和 dvm 控制器是同级对象。 在您的 passwordValidator 指令中,您需要在其控制器中使用 dvm 对象。使用 dvm 对象设置 person.showMsg 与做的一样:

$scope.dvm.person.showMsg = <value>

dvm 对象无法访问 $scope 上的 person 对象,因为它们是同级对象。所以你需要使用 $scope 本身来访问 person 对象。你需要做:

$scope.person.showMsg = <value>

虽然这假设范围内存在 person,但这是一个危险的假设。