Использование контроллера в качестве синтаксиса обновляет только одну из областей

Я немного запутался, когда дело доходит до controller as синтаксис, как я никогда не работал с ним раньше. Я хотел бы знать правильный способ исправить это. Не удалось найти подобную проблему при поиске.

У меня есть меню и кнопка, которая переключает меню. У меню есть своя область действия, а у кнопки - другая, так как они находятся в двух отдельных файлах и контейнерах.

Когда я нажимаю кнопку, он только обновляет nav.isActive в пределах кнопки. Я создал сервис для хранения состояния, что мне не нужно делать, когда я думаю об этом.. Должен ли я? Потому что единственный способ наблюдать, если это значение меняется, с помощью наблюдателя, который потребовал бы от меня использования $scope поскольку this не имеет $watch Однако я хотел бы избежать этого настолько, насколько смогу, поскольку это повлияет на производительность, что важно в этом проекте.

Как правильно изменить переменную "scope" из другой "scope" при использовании 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 ответа

Решение

Ваша проблема в том, что 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:

Когда контроллер подключен к DOM через директиву ng-controller, Angular создаст новый объект Controller, используя указанную функцию конструктора Controller. Новая дочерняя область будет создана и сделана доступной в качестве параметра ввода для функции конструктора Контроллера как $scope.

Кроме того, директива ng-controller имеет область видимости, которая наследуется от родительской области видимости. Таким образом, вы также можете определить общие данные в родительском. Он будет доступен в области "NavCtrl". Но поскольку вы хотите использовать контроллер в качестве synax, одним из способов будет обмен данными с помощью службы.

Однако мне не нравится подход с директивой ng-controller. Другое решение состоит в том, чтобы заменить его иерархией директив, где дочерним директивам потребуется родительская директива. Также используйте свойство 'controllerAs' там.

Другие вопросы по тегам