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

12,772

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.
      });
    }
  });
});
Share:
12,772
fusio
Author by

fusio

Updated on July 16, 2022

Comments

  • fusio
    fusio almost 2 years

    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",
            },
            "header@app": {
              templateUrl: "header.html"
            },
            "footer@app":{
              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?

  • fusio
    fusio over 9 years
    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) @Chris
  • Chris T
    Chris T over 9 years
    There is no mechanism currently to allow that. You could do some complicated conditionals yourself. I'll update the answer instead of typing it here.
  • fusio
    fusio over 9 years
    Thank you, very helpful!
  • claireablani
    claireablani almost 9 years
    @ChrisT If a sticky state has many many child states, and all of those child states have controllers, then by keeping all of the states alive if inactive, could there be any potential memory allocation issues?
  • Chris T
    Chris T almost 9 years
    Yes. You should definitely consider that
  • claireablani
    claireablani almost 9 years
    @ChrisT I see. That's too bad. It would otherwise be such an elegant solution for displaying nomadic modals and preserving user activity in various states. I counted watchers within each child state of the sticky state. Inactive states' controller bindings were not counted. So it would be rather that the controllers are taking up space merely by existing and defined?
  • claireablani
    claireablani almost 9 years
    @ChrisT Also when restoring a child state from inactive to active, the controller is destroyed and reinstantiated immediately afterwards at that point? It's not that they had already been destroyed upon transitioning to the inactive state in the first place?
  • Chris T
    Chris T almost 9 years
    Going from active to inactive and back, the controller is not destroyed or reinstantiated. Only when the state is entered or exited. Sticky states is so multiple states can be running fully, in parallel. (I almost called it parallel states)
  • dmr07
    dmr07 over 8 years
    @ChrisT I've switched to the exact same structure for my html and config, but one of my states using the app view contains a resolve which the controller uses. When I enter the modal state, the resolve variable becomes throws an unknown provider error. Is this suppose to happen in sticky states?
  • Chris T
    Chris T over 8 years
    Yes, any normal state gets resolves from itself and its parent states. Sticky states work the same way.
  • indusBull
    indusBull over 6 years
    How to pass param to modal in your example? I tried with $stateparm and it is always empty.