使用ui路由器进行范围和控制器实例化

时间:2015-03-17 18:30:24

标签: angularjs angularjs-scope angular-ui-router angularjs-routing

我对控制器实例化时很困惑。此外,嵌套状态时控制器如何实例化。我可能会对范围如何附加到视图和控制器感到困惑,也就是说,如果每个视图都有自己的控制器和范围,或者它们共享相同的范围。

有人可以解释控制器实例化的时间吗?在嵌套路由下,所有视图共享一个控制器和范围吗?当我切换状态并返回状态会发生另一个控制器实例化时会发生什么?

以下是我的路线(配置文件):

.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) ->

   $stateProvider

  .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/menu.html',
    controller: 'AppController'
  })

  .state('app.pincode', {
    url: '/pincode',
    views: {
      menuContent: {
        templateUrl: 'templates/pincode-yield.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.create', {
    url: '/create',
    views: {
      pincode: {
        templateUrl: 'templates/pincode-create.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.pincodeLogin', {
    url: '/login',
    views: {
     pincode: {
        templateUrl: 'templates/pincode-login.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.settings', {
    url: '/settings',
    views: {
      pincode: {
        templateUrl: 'templates/settings.html',
        controller: 'PincodeController'
      }
    }
  })

3 个答案:

答案 0 :(得分:33)

要获得更详细的答案,我们可以/应该观察源代码并查看文档。让我试着解释所有三个问题(也可以从代码和文档中引用)。

  

<强> 1。控制器什么时候实例化?

在这里,我们可以观察ui-view指令的代码:

[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]

控制器与视图相关。那些views,在.state()内定义为 views 对象:

.state('...', {
  // The view definition
  views : {
    '' : {
      template: ...
      controller: ...
      resolve: ..
    }
  },
  resolve: ...
}

因此,只要 view ui-view)填充了状态视图中定义的设置,它几乎就像标准,但增强指令

1)找到模板,
2)决议解决了 ...
x)控制器被实例化......

查看目标(ui-view指令)可以使用名称,并且可以由层次结构中的不同状态填充。

这可能意味着,一个视图(例如标题内部可能有一个内容,由定义并被替换通过孩子

// parent
.state('parent', {
  views : {
    '' : {...} // the main parent view, with ui-view="title"
    'title@parent' : { ...} // here we go and fill parent's ui-view="title"
  },
  ...
}

// child
.state('parent.child', {
  views : {
    'title' : { ...} // here we change the parent's target ui-view="title"
  },
  ...
}

以上状态定义将(每当我们在这两种状态之间转换时)执行:

  • $state.go('parent') - 'title@parent' : { ...}中定义的视图(模板,控制器...)将被注入目标ui-view="title"并按上述方式实例化

    < / LI>
  • $state.go('parent.child') - 几乎相同,只是视图将从子状态/视图定义'title' : { ...}中获取。这将取代ui-view="title"的内容,并将如上所述进行实例化

每次我们从父母到孩子和从孩子到父母时,都会发生这种情况。

  

<强> 2。在嵌套路由下,所有视图是否共享一个控制器和范围?

一个简单的答案是没有共同分享。

事实上,每个控制器都有自己的范围,即从父视图范围创建的范围。首先是文档:

  

What Do Child States Inherit From Parent States?

     

...

     

Scope Inheritance by View Hierarchy Only

     

请记住,只有嵌套状态的视图时,范围属性才会继承状态链。范围属性的继承与状态的嵌套无关,也与视图嵌套(模板)无关。

     

完全有可能您有嵌套状态,其模板在您网站中的各种非嵌套位置填充ui-views。在这种情况下,您不能期望在子状态视图中访问父状态视图的范围变量。

因此,只要我们的controller (以及视图,模板,控制器......)注入父目标ui-view="...",继承范围:

newScope = scope.$new();

简而言之,意味着 JS对象 (例如scope.Model = {}可以在子级和父级之间共享。

$scope.Model.id = 1; // will refer to the same id in both parent & child

但是 ,基本的Javascript类型不会通过引用传递,因此它们的值不会在范围之间自动同步:

// set in parent
$scope.id = 1;
// in child after inherted still === 1
$scope.id = 2; // now 2 for a child, different value in parent - still === 1

这里有关于原型继承的更多信息: What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

  

第3。当我切换状态并返回状态时会发生什么 - 另一个控制器是否实例化?

这取决于。

如果父子视图(请记住上面的ui-view="title"被子视图替换,然后重新创建(从子级转换为父级) - 这种控制器将被重新初始化(如上所述)。

但是当我们谈论主要父视图 (通常是未命名的)时,它代表 (例如未命名的使用控制器'ParentMainCtrl'查看下面的

.state('parent', {
  views : {
    '' : {  //  // the main parent view
      controller: 'ParentMainCtrl',
    }
    'title@parent'
    'tooltip@parent'
  },

然后我们可以确定不会重新实例化这样的控制器。它生活在其所有孩子的一生中,加上父母的一个(没有选择孩子状态)

要重新加载此视图/控制器,我们必须使用选项reload

$state.go(to, params, options)

  

...   选项选项对象。选项包括:

  • ...
  • 重新加载 - {boolean=false} ,如果为true,即使状态或参数没有更改,也会强制转换,即重新加载相同的状态。它与reloadOnSearch不同,因为当你想在一切都相同时强制重新加载时你会使用它,包括搜索参数。

希望有所帮助。有关详细信息,请查看以下资源:

答案 1 :(得分:2)

只要您访问特定状态,控制器就会被实例化。例如,在第一次访问app.pincode.pincodeLogin时,会构建一个AppController和两个PincodeControllers,每个都有自己的视图,假设您拥有正确的模板。切换到'app.pincode.settings'会破坏最里面的控制器并用新的控制器替换它,但是不会触及层次结构中较高的两个控制器。范围遵循标准AngularJS&#39;继承模式,它们不是孤立的。

您可能希望删除子状态中的控制器(并处理父控制器中的业务逻辑)或为每个状态设置不同的控制器 - 不同模板和视图的相同控制器通常是设计不良的标志

答案 2 :(得分:2)

第一次加载相应的视图时,控制器会被实例化。

例如,如果您有3个与3个控制器关联的选项卡 - 则与默认视图关联的控制器将实例化First。接下来,当您加载其他视图时,关联的控制器也会被实例化。

但有趣的是,一旦在DOM中加载了一个视图 - 它默认是缓存的。当视图被导航离开时,其元素将保留在DOM中,并且其范围与$ watch循环断开连接。导航到已缓存的视图时,其范围将重新连接,并且DOM中剩余的现有元素将成为活动视图。