ui 路由器 - 带有共享控制器的嵌套视图

ui router - nested views with shared controller

我有一个抽象父视图,旨在与其嵌套视图共享一个控制器。

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController'
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html'
})

路由按预期工作。

问题是,当我从其中一个嵌套视图更新 $scope 变量时,更改没有反映在视图中。当我从父视图执行相同操作时,它工作正常。这不是需要 $apply.

的情况

我的猜测是 editController 的新实例正在为每个视图创建,但我不确定为什么或如何修复它。

此处的问题与此问答有关:How do I share $scope data between states in angularjs ui-router?

解决方法隐藏在:

Understanding Scopes

In AngularJS, a child scope normally prototypically inherits from its parent scope.
...

Having a '.' in your models will ensure that prototypal inheritance is in play.

// So, use
<input type="text" ng-model="someObj.prop1"> 
// rather than
<input type="text" ng-model="prop1">.

还有这个

Scope Inheritance by View Hierarchy Only

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

既然如此,我们应该在编辑 Controller 中执行此操作

controller('editController', function ($scope) {
  $scope.Model = $scope.Model || {SomeProperty : "xxx"};
})

我们甚至可以重用 controller: 'editController' (我们不必这样做,因为 $scope.Model 会在那里 - 感谢继承)

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController'
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html',
    controller: 'editController'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html',
    controller: 'editController'
})

现在,同一个控制器将被实例化多次(父级所有子级)但 $scope.Model 将仅启动一次(在父级内部)并且随处可用

勾选这个similar working example here

基于

的评论

Is it possible to do this when using the controllerAs pattern giving the child state it's own controller?

我决定附加另一个解决方案,使用 controllerAs 同时保持

a working plunker

状态现在将有不同的控制器,父状态将其命名为 "parentCtrl" (不会在子范围内被子控制器覆盖)

 .state("main", {
      controller:'mainController',
      controllerAs: "parentCtrl",
      ...
  .state("main.1", {
      parent: 'main',
      controller:'child1Controller',
      controllerAs: "ctrl",
      ...
  .state("main.2", {
      parent: 'main',
      controller:'child2Controller',
      controllerAs: "ctrl", 
      ... 

这些是控制器:

.controller('mainController', function ($scope) {
    this.Model =  {Name : "yyy"};
})
.controller('child1Controller', function ($scope) {
    $scope.Model = $scope.parentCtrl.Model;
})
.controller('child2Controller', function ($scope) {
    $scope.Model = $scope.parentCtrl.Model; 
})

实际查看 here

另一种选择resolve

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController',
    resolve: {
        baseData: function() {
            return {};
        }
    }
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html',
    controller: 'editController'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html',
    controller: 'editController'
})


.controller('editController', function (baseData) {
    baseData.foo = baseData.foo || 'bar';
});

在子控制器中你可以做:

angular.extend($scope, $scope.$parent)

如果控制器使用别名,例如'vm' 你可以这样做:

let vm = angular.extend(this, $scope.$parent.vm);