使用控制器作为语法仅更新其中一个范围

Using controller as syntax only updates one of the scopes

我对 controller as 语法有点困惑,因为我以前从未使用过它。我想知道解决这个问题的正确方法。一直没能搜索到类似的问题。

我有一个菜单和一个切换菜单的按钮。菜单有自己的作用域,按钮有另一个作用域,因为它们位于两个独立的文件和容器中。

当我单击按钮时,它只会更新按钮范围内的 nav.isActive。我创建了一个用于存储状态的服务,当我想到它时我不应该这样做......应该吗?因为观察该值是否发生变化的唯一方法是使用观察者,这需要我使用 $scope 因为 this 没有 $watch 函数,但是,我想尽可能避免这种情况,因为它会影响性能,这在这个项目中很重要。

使用 controller as 语法时,从另一个 "scope" 更新一个 "scope" 变量的正确方法是什么?

控制器:

nav.controller('NavCtrl', ['navState', function(navState) {

  var nav = this;

  nav.menu = [
    {icon: 'color_lens', href: ''},
    {icon: 'color_lens', href: 'about'},
    {icon: 'color_lens', href: 'contact'},
    {icon: 'color_lens', href: 'logout'},
    {icon: 'color_lens', href: 'faq'}
  ];

  nav.toggleMenu = function() {
    nav.isActive = navState.checkState();
  }

}]);

将值从一个作用域传递到另一个作用域的服务:

nav.service('navState', [function() {

  var isActive = false;

  this.checkState = function() {

    isActive = !isActive;

    return !isActive;
  }
}]);

菜单标记(menu.html):

<nav class="si-wrapper si-dark" ng-controller="NavCtrl as nav" ng-class="{active: nav.isActive}">
  <ul class="si-list">
    <li class="si-item" ng-repeat="item in nav.menu">
      <a href="#/{{item.href}}">
        <div class="si-inner-item">
          <i class="material-icons md-36" ng-bind="item.icon"></i>
        </div>
      </a>
    </li>
  </ul>
  <h1>{{nav.isActive}}</h1> <!-- This doesn't change -->
</nav>

切换菜单的按钮(header.html):

<div ng-controller="NavCtrl as nav">
  <button ng-click="nav.toggleMenu()">Toggle</button>
  <span>{{nav.isActive}}</span> <!-- This updates however -->
</div>

您的问题是没有为其中一个控制器设置 nav.isActive。基本上每当你使用 ng-controller 时,都会创建一个新的控制器(和 $scope)。因此,对于您的每个控制器,需要为相关视图设置 $scope.isActive 以引用它。

在您发布的代码中,isActive 仅在 toggleMenu() 为 运行 时设置,这仅在 header.html.

中发生

为了让您的代码正常工作,只需在控制器负载上设置 isActive。例如:

nav.controller('NavCtrl', ['navState', function(navState) {
    // put isActive on the scope on controller load
    this.activeState = navState.getState();

    nav.toggleMenu = function() {
        navState.toggleState();
    };
}]);

您需要通过分离状态访问和状态操作来改善您的服务。还将它包装在容器对象中将确保您不会有任何范围层次结构问题。

nav.service('navState', [function() {

    var state = {
        isActive: false
    };

    this.toggleState = function() {
        state.isActive = !state.isActive;
    };

    this.getState = function(){
        return state;
    };
}]);

然后你需要在视图中使用 `activeState.isActive'。

现在您将拥有一个具有可共享状态的服务,以及两个在加载时都引用相同服务的控制器。然后在您的菜单视图中,当您切换状态时,两个控制器范围都会更新。

来自 angularjs 文档:

When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function. A new child scope will be created and made available as an injectable parameter to the Controller's constructor function as $scope.

此外,ng-controller 指令有一个从其父范围继承的范围。因此,您还可以在父级中定义共享数据。它可以在 'NavCtrl' 范围内访问。但是,由于您想将控制器用作 synax,一种方法是在服务的帮助下共享数据。

但是,我不喜欢使用 'ng-controller' 指令的方法。另一种解决方案是将其替换为指令层次结构,其中子指令将需要父指令。也在那里使用 'controllerAs' 属性。