Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sub-state with multiple parents / route for modal that opens over several states

I have a abstract profile state, which has multiple child states (for different tabs of the profile page), and then I want to have another child state of profile be a modal. I've implemented it something like this:

$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();
            });
        }]
    })

This works great, except for the fact that because editprofile is a sibling of squares and circles, when that state is active and the modal is in view, the squares or circle state is unloaded, and loaded back in again when the modal is closed.

Is there any way to have those states remain active when the profile.editprofile state is active? I'm after something like state..editprofile.

like image 698
Josh Hunt Avatar asked Mar 27 '14 23:03

Josh Hunt


1 Answers

As there is currently no ideal solution, I have come up with a reasonably elegant solution. My code is generalized, easy to understand and commented so that it should be easy to adapt to any project.

See the comments in the code for the most significant points.

Live Demo (click).

Sample States

$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('^');
        });
      }
    ]
  }
}

Controller

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

View

<a ng-click="goToModalState()">Open Modal</a>
like image 91
m59 Avatar answered Nov 15 '22 04:11

m59