具有多个父母的子状态/模态路径,可在多个州打开

时间:2014-03-27 23:12:21

标签: angularjs angular-ui-router

我有一个抽象的profile状态,它有多个子状态(对于配置文件页面的不同选项卡),然后我希望另一个子状态的配置文件是一个模态。我已经实现了这样的事情:

$stateProvider
    .state('profile', {
        url: '/profile/:profileID',
        templateUrl: 'profile.html',
        controller: 'ProfileCtrl',
        abstract:true,
        resolve: {
            user: ...
        }
    })
    .state('profile.circles', {
        url: '',
        templateUrl: 'profilecircles.html',
        controller: 'profilecirclesCtrl',
        resolve: { circle: ... }
    })
    .state('profile.squares', {
        url: '/collections',
        templateUrl: 'profilesquares.html',
        controller: 'profilesquaresCtrl',
        resolve: { squares: ... }
    })
    .state('profile.editprofile', {
        url: '/edit',
        onEnter: ['$window','$modal', function($window, $modal) {
            $modal.open({
                templateUrl: 'editprofile.html',
                controller: 'editProfileCtrl',
                resolve: {
                    user: ...
                }
            }).result.then(function() {
                $window.history.back();
            },function() {
                $window.history.back();
            });
        }]
    })

这很有效,除了因为editprofile是正方形和圆形的兄弟,当该状态处于活动状态并且模态处于视图中时,正方形或圆形状态被卸载,并在模态时再次加载回来已关闭。

当profile.editprofile状态处于活动状态时,有没有办法让这些状态保持活动状态?我喜欢state..editprofile

之类的东西

4 个答案:

答案 0 :(得分:3)

由于目前还没有理想的解决方案,我提出了一个相当优雅的解决方案。我的代码是通用的,易于理解和评论,因此它很容易适应任何项目。

请参阅代码中的注释以获取最重要的观点。

Live Demo (click).

样本州

$stateProvider

// modal will open over this state from any substate
.state('foo', {
  abstract: true,
  url: '/:fooProp',
  templateUrl: 'foo.html',
  controller: 'FooController'
})
.state('foo.main', {
  url: '',
  templateUrl: 'foo-main.html',
  controller: 'FooMainController'
})
.state('foo.bar', {
  url: '/bars/:barId',
  templateUrl: 'foo-bar.html',
  controller: 'FooBarController'
})

// append /modal route to each `foo` substate
.state('foo.main.modal', getModalState())
.state('foo.bar.modal', getModalState())

;

function getModalState() {
  return {
    url: '/modal',
    onEnter: [
      '$modal',
      '$state',
      function($modal, $state) {
        $modal.open({
          templateUrl: 'foo-modal.html',
          controller: 'FooModalController'
        }).result.finally(function() {
          // go to parent state - the current `foo` substate
          $state.go('^');
        });
      }
    ]
  }
}

控制器

$scope.goToModalState = function() {
  // go to this state's `modal` state
  $state.go($state.current.name+'.modal');
};

视图

<a ng-click="goToModalState()">Open Modal</a>

答案 1 :(得分:2)

除非您想要放弃模态实现,否则我建议在profile.html中为editprofile.html设置2个视图,为profilecircles.htmlprofilesquares.html设置其他视图,如下所示:

// profile.html
...
<div class="" ui-view="edit" autoscroll="false"></div>
<div class="" ui-view="content" autoscroll="false"></div>
...

// state config
$stateProvider
.state('profile', {
    url: '/profile/:profileID',
    templateUrl: 'profile.html',
    controller: 'ProfileCtrl',
    abstract:true,
    resolve: {
        user: ...
    }
})
.state('profile.circles', {
    url: '',
    views: {
        edit@: {
            templateUrl: 'editprofile.html',
            controller: 'editProfileCtrl'
        },
        content@: {
            templateUrl: 'profilecircles.html',
            controller: 'profilecirclesCtrl'
        }
    }
    resolve: { circle: ... }
})
.state('profile.squares', {
    url: '/collections',
    views: {
        edit@: {
            templateUrl: 'editprofile.html',
            controller: 'editProfileCtrl'
        },
        content@: {
            templateUrl: 'profilesquares.html',
            controller: 'profilesquaresCtrl'
        }
    }
    resolve: { squares: ... }
})

然后是实际显示/隐藏编辑个人资料视图的难点。但这可以通过一些切换按钮或在控制器中验证操作后完成。

答案 2 :(得分:1)

ui-router的意思是状态嵌套与url嵌套匹配。这意味着,如果你有:

profile.circles with a url: /profile/123
profiles.squares with a url: /profile/123/collections
profiles.edit with a url: /profile/123/edit

你不能指望profile.squares和profiles.edit同时处于活动状态,因为它们是两个完全不同的网址。但是有可能:

profiles.circles.editprofile with a url: /profile/123/edit

这会使profile.circles在你的模态中保持活动状态,因为它是父状态。 但是对于profiles.squares,如果你想要一个代表editprofile的状态,你需要这样的东西:

profiles.squares.editprofile with a url: /profile/123/collection/edit

不幸的是,如果你想把编辑作为一种状态,没有别的方法。

答案 3 :(得分:0)

您可以使用ui-router-extras指定标签状态sticky: true。导航到兄弟时保留粘性状态,对标签特别有用。

要使用它,您必须为每个粘性状态创建一个命名视图(您可以隐藏非活动状态,但请参见下文)。

API page描述了必要的步骤:

  1. 使用sticky: true
  2. 标记状态
  3. 在状态上声明一个命名视图,该视图将在父状态模板中定位命名的ui-view,例如views: { bar: { /* bar named-view definition */ } }
  4. 将命名的ui-view添加到父状态的模板,例如<div ui-view="bar" />
  5. 可选地,在未激活状态时隐藏命名的ui视图,例如, <div ui-view="bar" ng-show="$state.includes("foo.bar") />