Angular ui-router: keep same ui-view for child

2020-03-26 04:41发布

问题:

I need child state be able to use parent state's resolve functions. But I also need to keep same ui-view for both states. Here's a fiddle. And there's a code

    $stateProvider
        .state('parent', {
            url: "/",
            template: '<p>Hello {{parent.one}}</p><br>'
                    + '<button ng-click="goToChild()">child</button><br>',
            // this one below work but I don't need it
            // template: '<p>Hello {{parent.one}}</p><br>'
            //      + '<button ng-click="goToChild()">child</button><br>'
            //      + '<div ui-view></div>',
            resolve: {
                test: function() {
                    return 1;
                }
            },
            controller: function($scope, $state, test) {
                $scope.parent = { one: test };
                $scope.goToChild = function() {
                    $state.go('parent.child');
                }
            }
        })
        .state('parent.child', {
            url: "/child",
            template: '<p>Hello {{child.one}}</p>',
            controller: function($scope, test) {
                $scope.child = { one: test };
            }
        })
    $urlRouterProvider.otherwise('/');

回答1:

There is a working plunker.

The answer should be hidden/revealed in this two states definition:

parent with multi views

  .state('parent', {
    url: "/",
    views: {
      '@': {
        template: '<div ui-view=""></div>',
        controller: function($scope, $state, test) {
          $scope.parent = { one: test };
          $scope.goToChild = function() {
            $state.go('parent.child');
          }
        }
      },
      '@parent': {
        template: '<p>Parent says: hello <pre>{{parent | json}}</pre></p>'
                + '<br><button ng-click="goToChild()">child</button><br>',
      }
    },
    resolve: {
       test: function() { return 1; },
    },
  })

Child consuming parent resolve, and having its own

  .state('parent.child', {
    url: "^/child/:id",
    template: '<p>Child says: hello <pre>{{child | json }}</pre></p>',
    resolve: {
      testChild: function() { return 2; },
    },
    controller: function($scope, test, testChild) {
      $scope.child = {
        one: test,
        two : testChild,
        parent: $scope.parent,
      };
    },
  })

Check it here

And how it works? Well, it all is based on the:

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.

and also:

View Names - Relative vs. Absolute Names

Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname@statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.

For example, the previous example could also be written as:

  .state('report',{
    views: {
      'filters@': { },
      'tabledata@': { },
      'graph@': { }
    }
  })

So, the above documentation cites are the core of the plunker. The parent uses multi views, one of them is unnamed - and will be used for inheritance. Parent also injects into that view its own "parent" view. The Resolve of a parent is in place...

Child now injects into anchor of its parent, which does have all the stuff needed. That means, that child does inherit scope and also resolve stuff. It shows its own resolve as well...