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

Change parent controller model through directive $watch using controllerAs syntax

本文关键字:控制器 模型 指令 watch 语法 controllerAs 使用      更新时间:2023-09-26

我是新的控制器的语法角,只是试图了解它是如何与指令工作。我创建了一个密码验证指令。我想根据条件使一些标志为真,这些将在父模板中用于显示错误消息。我不明白我怎么能做到这一点!

JSFiddle

<

视图/strong>

<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() {
    }
});

我特别想知道为什么和如何下面的手表工作良好!

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

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

我知道这不是你问题的一部分,我会得到它,但使用指令'ng-controller'是一个反模式。如果你感兴趣,为什么我可以在另一篇文章中解释,但简而言之,它使代码更难理解。

现在,让我们进入你问题的核心。

从阅读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对象没有访问person对象的方法,因为它们是$作用域上的兄弟对象。因此需要使用$作用域本身来访问person对象。你需要这样做:

$scope.person.showMsg = <value>

虽然这里假设person存在于作用域中,但这是一个危险的假设。

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

// 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是未定义的,因为你在同一个作用域中使用了控制器,所以没有创建新的变量dvm,所有的dvm控制器变量都在父作用域中初始化。

这意味着你不需要将person controller"注入"到指令中,因为你已经在指令范围中有了控制器实例。所以只要像这样设置你的变量'showMsg',它就会像魔术一样工作!

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

我为你做了一个小提琴:JSFiddle