Angular 摘要周期 运行 但 ng-bind 值未更新

Angular Digest cycle being ran but ng-bind value not updating

我有一个包含导航栏的父视图,在该视图内部我有一个 <div ui-view> 元素,它呈现我所在的任何子视图。

我想根据子视图的路线有条件地 show/hide 父视图中的导航栏。现在,我有这个:

<nav ng-show="!vm.hideNavbar">

第一次加载我的应用程序时,vm.hideNavbar 设置为 true,这按预期工作。

vm.hideNavbar改为false后,绑定值不更新。还是true.

我应用中的每个控制器都扩展了这个 BaseController:

export class BaseController {
        public hideNavbar: boolean;

        constructor(public $scope: IBaseScope, private $state: ng.ui.IStateService) {
            if ($state.current.url === '/login') {
                this.hideNavbar = true;
            } else {
                this.hideNavbar = false;
            }
            $scope.vm = this;
        }
 }

因此,每次加载新控制器时,它都会调用 BaseController 的构造函数并有条件地设置 $scope.vm.hideNavbar。如果我在这个构造函数的末尾立即 运行 $scope.$apply(),angular 会抛出错误,说明摘要周期已经在 运行.

因此,摘要周期正在 运行,但我认为的值没有更新。我唯一的想法是,自从我的初始控制器和我导航到的控制器都扩展了这个控制器以来,我已经实例化了 BaseController 的多个副本。所以,现在,我的绑定值vm.hideNavbar还在看老控制器

我的方向正确吗?我该如何解决这个问题?

在这种情况下,我建议使用 view inheritance (不是 controller,不是 state。在此处查看更多详细信息:

  • How do I share $scope data between states in angularjs ui-router?
  • How to inherit resolve data in ui-router

a working example

我们需要的是 'root' 状态。它将是任何其他 state (states family)super parent。这可能是状态定义:

$stateProvider
  .state('root', {
      abstract: true,
      templateUrl: 'layout.tpl.html',
      controller: MyNamespace.RootCtrl,
  })

  .state('login', {
      parent: "root",
      url: "/login",
      templateUrl: 'tpl.html',
      controller: MyNamespace.LoginCtrl,
  })
  .state('home', {
      parent: "root",
      url: "/home",
      templateUrl: 'tpl.html',
      controller: MyNamespace.HomeCtrl,
  })

甚至其他一些州等级制度也将从 'root' 州开始:

$stateProvider
  .state('parent', {
      parent: "root",
      url: "/parent",
      templateUrl: 'tpl.html',
      controller: MyNamespace.ParentCtrl
  })
  .state('parent.child1', { 
      url: "/child1",
      templateUrl: 'tpl.html',
      controller: MyNamespace.Child1Ctrl
  })
  .state('parent.child2', { 
      url: "/child2",
      templateUrl: 'tpl.html',
      controller: MyNamespace.Child2Ctrl
  })

我们可以看到很多controllers:...被定义,这里是:

module MyNamespace {
    // the real SUPER parent of all states
    // but it is about VIEW inheritance (its $scope)
    // not about controller hierarchy
    export class RootCtrl extends BaseController {
    }

    export class HomeCtrl extends BaseController {
    }
    export class LoginCtrl extends BaseController {
    }
    export class ParentCtrl extends BaseController {
    }
    export class Child1Ctrl extends BaseController {
    }
    export class Child2Ctrl extends BaseController {
    }
}

如片段评论中所述 - 存在继承,但仅在代码级别。传递的 $scope 由视图层次结构继承。

视图层次结构中的第一个控制器是 RootCtrl,它实际上是唯一一个分配(创建)共享参考模型的控制器 rootSetting : {}

它们都源自这个控制器基础:

module MyNamespace {
    export interface IRootSetting {
        hideNavbar: boolean;
    }
    export interface IMyRootScope extends ng.IScope {
        rootSetting: IRootSetting
    } 
    export interface IBaseScope extends IMyRootScope {

    }
    export class BaseController {
        public hideNavbar: boolean;
        static $inject = ['$scope', '$state'];

        constructor(public $scope: IBaseScope, 
                 protected $state: ng.ui.IStateService) {

                  // will be in fact assigned in the RootCtrl only
                  // all others (children) will get that reference
                  // via scope inheritance
                  $scope.rootSetting = $scope.rootSetting || {hideNavbar: false}; 

            if ($state.current.url === '/login') {
                this.$scope.rootSetting.hideNavbar = true;
            } else {
                this.$scope.rootSetting.hideNavbar = false;
            }
        }
    }
}

有了这个根模板:

<div>      
  <div ng-if="!rootSetting.hideNavbar"> 
   ... // navbar
  </div>      

  <div ui-view="">
      // standard content of child views
  </div>      
</div>

我们可以看到,这里我们评估共享参考模型rootSetting及其属性hideNavbar

这就是view inheritanceUI-Router的真正优势。

实际查看 here