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

时间:2015-11-14 22:01:58

标签: javascript html angularjs angularjs-controlleras

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

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

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

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

控制器:

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>

2 个答案:

答案 0 :(得分:2)

您的问题是没有为其中一个控制器设置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&#39;在你的视野内。

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

答案 1 :(得分:0)

来自angularjs docs:

  

当Controller通过ng-controller指令附加到DOM时,Angular将使用指定的Controller的构造函数实例化一个新的Controller对象。将创建一个新的子范围,并将其作为可注入参数提供给Controller的构造函数作为$ scope。

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

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