如何在父状态下从嵌套状态访问参数?

时间:2015-03-16 04:53:53

标签: javascript angularjs angular-ui-router state

我有一个例子here。我如何访问父状态控制器中的'itemId'参数?不得重新加载父视图。

angular.module('app',['ui.router'])
.config(function($stateProvider){
   $stateProvider.state('step', {
            url: '/orders/:step',
            templateUrl: 'parent.html',
            controller: function ($scope, $stateParams) {
                $scope.itemId = $stateParams.itemId;
                $scope.step = $stateParams.step;
            }
        })

        .state('step.item', {
            url: '/:itemId',
            templateUrl: 'child.html',
            controller: function ($scope, $stateParams) {
                $scope.itemId = $stateParams.itemId;
                $scope.step = $stateParams.step;
            }

        });
}).controller('SimpleController', function($scope, $state){
  $scope.items = [1,2,3,4,5,6];
  $scope.steps = ["first", "second"];
})

我只看到两种方式:

  1. 添加服务并将其注入两个控制器
  2. 从子控制器访问父作用域并传递参数

    但两者都促使我在父范围内添加观察者。 也许我可以更轻松地完成它?

4 个答案:

答案 0 :(得分:4)

首先,您需要认识到父状态控制器在您输入其子状态的子树时只运行一次,因此在其子项之间切换不会重新运行控制器。

这就是说,如果您希望itemId参数始终保持最新,则需要$watch(您试图避免使用此参数)。

第一次,你可以在父母的州里收集itemId这样的内容:

$scope.itemId = $state.params.itemId;

如果您需要保持最新状态,那么您需要注意更改,例如:

$scope.$watch(function(){
  return $state.params;
}, function(p){
  $scope.itemId = p.itemId;
});

plunker

同样,如果您只需将其放在视图中,则在范围上设置$state

$scope.$state = $state;

并在视图中:

<div>parent /orders/{{step}}/{{$state.params.itemId}}</div>

修改

我想另一种方法是在父级上调用范围公开的函数来更新值。我不喜欢这种方法,因为它依赖于范围继承(并不总是与状态继承相同),并且很难跟踪大型应用程序中的范围继承。但它不需要$ watch:

在父控制器中:

$scope.updateItemId = function(itemId){
   $scope.itemId = itemId;
};

并在子控制器中:

if ($scope.updateItemId) $scope.updateItemId($stateParams.itemId)

答案 1 :(得分:3)

我可以看到,您已经找到了答案,但我想向您展示不同的方法。我甚至会将其命名为&#34;用路径构建的UI-Router&#34;

已在UI-Router example application中显示,如果我们转到某个ID = 42 like here的子状态,我们也可以更改另一个,而不是主视图({{ 1}}在这种情况下查看)

有一个working example with your scenario,表明一切都在行动。

我们使用的是 Multiple Named Views

父状态现在定义了根视图,该视图被注入 root / index.html 内的未命名hint

新的ui-view=""

parent.html

正如我们所看到的,它还包含另一个视图目标(比未命名的) - 例如 <div ui-view="title"></div> <div ui-view=""></div> 我们立即填写另一个模板...在父状态:

ui-view="title"

小孩?它可以继续处理主区域......但也可以更改标题区域。两种观点都是独立的,属于儿童。

$stateProvider.state('step', {
  url: '/orders/:step',
  views : {
    '': {
      templateUrl: 'parent.html',
    },
    'title@step': {
      templateUrl:'parent_title_view.html',
    }
  }
})

因此,没有观察者,没有任何内容......默认情况下,.state('step.item', { url: '/:itemId', views : { '': { templateUrl: 'child.html', }, 'title': { templateUrl:'child_title_view.html', } } 未附带此内容。我们只是使用子实现来调整许多地方(视图)。我们仍然可以在父级中为其内容提供一些默认值。

检查example here。希望看到它有点不同会有所帮助...

答案 2 :(得分:0)

我不确定这是否能真正解决你的问题,但你可以做到

   $stateProvider.state('step', {
            url: '/orders/:step/:itemId',
            templateUrl: 'parent.html',

http://plnkr.co/edit/sYCino1V0NOw3qlEALNj?p=preview

这意味着父状态将在途中收集itemID。

答案 3 :(得分:0)

在父状态的解析函数中包含$ state

.state('parent', {
                url: '/parent',
                controller: 'parentController',
                resolve: {
                params: ['$state', function ($state) {
                            return  $state.params;
                        }]
                }
            })

然后在父控制器中注入被调用的变量

app.controller('parentController', ['$scope', 'params',
function ($scope, params) {

  $scope.params = params; 

}]);
以这种方式,孩子和父母都可以使用params。