5

I want to temporarily change the browser url when the ui bootstrap modal is opened ( The page behind should remain as is, only the url changes ). When the modal is closed the url should be reverted back to the original one.

Steps :

  1. User loads the page
    • url : xyz.com/home
  2. User clicks a link opens a modal
    • url : xyz.com/detail/123
    • possible solution : changing url with html5 push state
    • problem : Angular ui-router tries to run its routes as per the changed url, eventually changing the background page.
  3. User closes the modal
    • url : xyz.com/home
    • possible solution : html5 pop state
    • problem : Reloads the background page, which kills the purpose

Example implementation : Pinterest pins and their pin details popup.

Kunal Dethe
  • 1,254
  • 1
  • 18
  • 38
  • 1
    You need to create your modal as a state in order to achieve this. – theaccordance Jun 06 '16 at 16:42
  • My modal is opened from an isolate scope directive, basically can be invoked from any state in the application. Does the modal state need the parent state to be abstract ? Have you worked with angular ui-router-extras sticky modal ? – Kunal Dethe Jun 06 '16 at 16:47
  • 4
    http://plnkr.co/edit/qgt0RkEnXDPDTdMJPIfy?p=preview – theaccordance Jun 06 '16 at 17:11
  • Will you please post a snippet of your code? – webdev5 Jun 07 '16 at 19:54
  • Add a state with the same parameters except its name – chabeee Jun 09 '16 at 12:30
  • The term modal implies that I'm not navigating away from the page I'm on, so the URL shouldn't change. Why does it matter if the URL changes? This issue is trivial if you don't get hung up on changing the URL for some reason. – bryan60 Jun 11 '16 at 16:19
  • @bryan60, having URL changed you can open the modal directly, so you can post the link in twitter for example. – Alexander Kravets Jun 13 '16 at 05:01
  • @theaccordance please add your comment as the answer, I want to reward you the bounty. Also is there a way we can open the state in uibModal ? What i tried is onEnter of the modal state wrote the code to open the modal, as given [HERE](https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-open-a-dialogmodal-at-a-certain-state) The problem is that, modal not being a state, on close of it the url doesnot change back to the original one. Can you please help me with this? – Kunal Dethe Jun 20 '16 at 12:28

4 Answers4

1

You can use ui-router-extras sticky state to solve your problem. There is simple example with modal by the link. You should create two named views, one for main content (background) and one for modal.

<div ui-view="app"></div>
<div ui-view="modal"></div>

Mark the state, from what you want to access to modal as sticky: true in route definition.

.state('main', {
  abstract: true,
  url: '/',
  templateUrl: '_layout.html'
})
.state('main.index', {
  url: '',
  sticky: true,
  views: {
    'app': {
      templateUrl: 'index.html'
    }
  }
})
.state('main.login', {
  url: 'login/',
  views: {
    'modal': {
      templateUrl: 'login.html'
    }
  }
})

Also add an event for stateChangeSuccess:

$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
  if ((from.views && !from.views.modal) || !from.views) {
    $rootScope.from = from;
    $rootScope.fromParams = fromParams;
  }
});

so, when you need to close modal, you can just

$state.go($rootScope.from, $rootScope.fromParams);

There is small problem for that solution. If you reload page on the modal state, then the app ui-view will be empty.

E. Abrakov
  • 463
  • 2
  • 6
0

This can be achieved by having a nested state and triggering the modal using onEnter callback:

$stateProvider
  .state('contacts', {
    url: '/home',
    templateUrl: 'home.html',
    controller: function($scope, MyService){
      $scope.contacts = MyService.getContacts();
    }
  })
  .state('contacts.details', {
    url: "^/details/:id", // using the absolute url to not have the "/home" prepended
    onEnter: function($state, $uibModal) {
      var modal = $uibModal.open({
        templateUrl: 'details.html',
        controller: function($scope, $stateParams, MyService) {
            // get data from service by url parameter
            $scope.contact = MyService.getContact($stateParams.id);
        }
      });

      modal.result.finally(function() {
        $state.go('^'); // activate the parent state when modal is closed or dismissed
      });
    }
  });

This technique is described in the ui-router's FAQ.

Here the plunk. In this example the modal's scope is created as a child of the $rootScope - the default $uibModal's behavior when no scope is passed to it. In this case we should use the service in the modal's controller to obtain the data by url parameter.

To have master and details URLs look like these - xyz.com/home and xyz.com/detail/123 - we should use the absolute URL (^/details/:id) in the child state.

Using this solution you can open the detail URLs directly and still have both, master and detail states, activated properly, so sharing the detail URL is possible.

Alexander Kravets
  • 4,245
  • 1
  • 16
  • 15
  • In this solution You need to create a modal route state for each state You want the modal to be opened. And the url can't be like this: `url : xyz.com/home` for page and `url : xyz.com/detail/123` for modal – E. Abrakov Jun 12 '16 at 09:55
  • @E.Abrakov, yes, modal opening and closing logic should be written explicitly for every state. As for the URLs - you can use the absolute URL in the child state - see the updated answer and plunk. – Alexander Kravets Jun 12 '16 at 11:02
0

I think you can achive that with ngSilent module

https://github.com/garakh/ngSilent

using $ngSilentLocation.silent('/new/path/'); (once you open modal and again after closing it)

el vis
  • 1,302
  • 2
  • 16
  • 32
0

Managed to implement this using https://github.com/christopherthielen/ui-router-extras/tree/gh-pages/example/stickymodal

Kunal Dethe
  • 1,254
  • 1
  • 18
  • 38