Modal dialog using ui-router from any parent, how to correctly specify state?

All we need is an easy explanation of the problem, so here it is.

I am trying to open a modal dialog using Angular’s ui-router as explained here.

The goal is for the dialog to be accessible anywhere, a url is not necessarily needed but it would be nice if I could link to a page with the dialog open.

Here is the broken sample:

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

clicking on “menu” should open the dialog from either page.

The routing logic:

app.config(function($stateProvider,$locationProvider, $urlRouterProvider, modalStateProvider) {
  $urlRouterProvider.otherwise("/");
  $locationProvider.html5Mode(true);

  $stateProvider
    .state("app", {
      url: "",
      abstarct: true,
      views: {
        "" : {
          templateUrl: "main.html",
        },
        "[email protected]": {
          templateUrl: "header.html"
        },
        "[email protected]":{
          templateUrl: "footer.html"
        }
      }
    })

    .state("app.home", {
      url: "/",
      templateUrl: "home.html",
    })
    .state("app.content", {
      url: "/content",
      templateUrl: "content1.html",
    });


  modalStateProvider.state("app.home.menu", {
    template: "I am a Dialog!",
    controller: function ($scope) {
      $scope.dismiss = function () {
        $scope.$dismiss();
      };
    }
  });
});

It should not be a child of “app.home” since I want it to be accessible from anywhere. How can I achieve this?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

You can do this with UI-Router Extras “Sticky States”.

Updated plunk: http://plnkr.co/edit/GYMjzmBALlQNFWoldmxa?p=preview

Here is the UI-Router Extras modal demo: http://christopherthielen.github.io/ui-router-extras/example/stickymodal/#/


To update your plunk, I added UI-Router Extras:

  <script src="https://rawgit.com/christopherthielen/ui-router-extras/0.0.10/release/ct-ui-router-extras.js"></script>

var app = angular.module('plunker', ['ui.router', 'ct.ui.router.extras', 'ui.bootstrap']);

I added a named ui-view for the app and one for the modal

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

Then I marked your app state as sticky and made your modal state a top-level state. The effect is that you can navigate from any app.* state to the modal state… instead of exiting that state, it will only “inactivate” it, and it remains in the DOM.

$stateProvider
.state("app", {
  url: "",
  abstract: true,
  sticky: true,

modalStateProvider.state("menu", {

updated with response to question in comments:

quick question: if I give the “menu” state a URL (/menu) and the user goes to that URL (website.com/menu) is there a way to set a “default” sticky for the app view? (sort of default parent of the modals)

You can do this yourself using a bunch of silly logic.

  • Is this the initial transition?
  • Are we going to the modal state?
  • Then cancel the transition and go to the default state instead.
  • When that’s done, go to the modal state.

app.run(function($rootScope, $state) {
  $rootScope.$on("$stateChangeStart", function(evt, toState, toParams, fromState, fromParams) {
    if (fromState.name === "" && toState.name === "menu") {
      // fromState is the root state.  This is the initial transition.
      evt.preventDefault(); // cancel transition to modal.
      $state.go("defaultstate").then(function() { // Go to the default state
        $state.go(toState, toParams); // When that state has loaded, go back to the menu state.
      });
    }
  });
});

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply