Angularjs UI bootstrap temporarily changes the url on open and returns the original url on close

I want to temporarily change the browser url when ust bootstrap modal is open (the page behind should remain as it is, only the url is changed). When the modal object is closed, the URL should be returned back to the original.

Steps:

  • User is loading page
    • url: xyz.com/home
  • User clicks a link, opens a modal
    • url: xyz.com/detail/123
    • Possible solution: change url using html5 push state
    • problem: Angular ui-router tries to start its routes according to the changed URL, eventually changing the background image.
  • User closes modal
    • url: xyz.com/home
    • possible solution: html5 pop state
    • problem: reloading the background page that kills the target

Implementation example: Pinterest contacts and pop-ups of their contacts.

+5
source share
4 answers

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

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

Mark the state from which you want to access the modal as sticky: true in the 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 the modal, you can just

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

There is a small problem for this solution. If you reload the page in a modal state, the ui-view application will be empty.

+1
source

This can be achieved by having a nested state and starting the modality using the 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 method is described in the ui-router FAQ.

Here is the plunk . In this example, a modal region is created as a child of $rootScope - the default is $uibModal when no region is passed to it. In this case, we must use the service in the modular controller to receive data by the url parameter.

For the URLs of the main and detailed data to look like this: xyz.com/home and xyz.com/detail/123 - we must use the absolute URL ( ^/details/:id ) in the child state.

Using this solution, you can directly open the detailed URLs and still have both the basic and detailed states that are activated properly, so you can use a common URL.

0
source

I think you can achieve this with the ngSilent module

https://github.com/garakh/ngSilent

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

0
source

All Articles