AngularJS:如何在UI-Router中将一个状态设置为全局父级(使用模态作为公共部分)

AngularJS: How to set one state as a global parent in UI-Router (to use modal as common parts)

在 $stateProvider#state() 中,我使用 UI-Router 为 Bootrtrap-ui 模态定义如下。 reference

var state = {
    name: 'modala',
    parent: 'home',
    onEnter: function($modal, $state) {
        modalInstance = $modal.open({
            templateUrl: 'modala.html',
            controller: 'modalaCtrl',
            controllerAs: 'modal'
        });
        modalInstance.result['finaly'](function() {
            modalInstance = null;
            if ($state.$current.name === 'modala') {
                $state.go('^');
            }
        });
    },
    onExit: function() {
        if (modalInstance) {
            modalInstance.close();
        }
    }
};

我想在家以外的任何地方使用'modala'。

我不想创建很多 'modala'.

的定义

Is there a method to accept it, and to set what is necessary in parent?


添加说明

没有好的解决方案

  1. 不要将父级设置为模式状态。

    结果:打开模式时 window,不显示父级。

    pattern 1 example

  2. 模态状态名称为 ${parent.name}.modal 格式。

    结果:成功了。但是,关于一个模态window,需要定义很多状态。并且,每当我添加一个调用模态的父项时,都需要添加一个状态。

    pattern 2 exapmle

  3. 定义每个父节点的模态

    结果:与模式 2 相同。

    pattern 3 exapmle

您只需将 属性 parent: modala 添加到您定义的所有子状态即可设置父状态。

UI-Router 内置了一个解决方案,叫做 state decorator

decorator(name, func)

通过这种方式,我们可以创建一个切面,稍后将其注入到我们想要的任何状态中。这方面可以推动一些共同的全球环境。例如。 parentviews...

在这里查看示例:,小引用:

Allows you to extend (carefully) or override (at your own peril) the stateBuilder object used internally by $stateProvider. This can be used to add custom functionality to ui-router, for example inferring templateUrl based on the state name...

我们的场景有 a working example

我们需要的是装饰器定义,如下所示:

.config(['$stateProvider', 
  function($stateProvider) {

    $stateProvider.decorator('parent', function (state, parent) {
      // this is original, by configuration created parent
      var result = parent(state);

      // we can define where we do not want to change that default, configured
      var skipState = state.name === "home" 
                   || state.name === "modala"
                      // child already has that in parent
                   || state.name.indexOf(".") > 0 ;

      // and return taht default
      if(skipState) 
      { 
        return result;
      }

      // FINALLY - HERE
      //   we want to change parent, or even introduce new
      state.parent = 'modala'; 

      // and rebuild it
      result = parent(state);

      // new parent in place
      return result;

    });
}])

检查 action here

从题中有is updated plunker (the second try)

我们将在实际操作中看到装饰器的不同用法,如我的

中详细描述的

所以,首先,让我们有几个状态,例如'home'、'page1'、'page2' ... 我们希望为所有这些引入子状态 - 具有模态功能。该模态特征预计在所有子状态中 相同 - 但这些将属于不同的父级。

为了实现它,我们可以使用这样的状态定义:

.config(function($stateProvider) {
  // we just define empty child state for each existing parent
  $stateProvider.state('home.generalModal',  {});
  $stateProvider.state('page1.generalModal', {});
  $stateProvider.state('page2.generalModal', {});
})

如果我们以这种方式劫持装饰器,那就足够了:

.config(['$stateProvider', 
  function($stateProvider) {

    var endsWith = function(stringToBesearched, valueToBeFound) {
      return stringToBesearched.slice(-valueToBeFound.length) === valueToBeFound;
    }

    $stateProvider.decorator('data', function (state, dataBuilder) {
      // this is original, by configuration created parent
      var data = dataBuilder(state);

      // we can define where we do not want to change that default, configured
      // in our case, we extend every state which ends with .generalModal
      var skipState = !endsWith(state.name, ".generalModal")

      // and return taht default
      if(skipState) 
      { 
        return data;
      }

      // the modal instance per this state instance
      var modalInstance;

      // definition of the onEnter
      var onEnter = function($modal, $state) {
          console.log("Entering state: " + $state.current.name)
          modalInstance = $modal.open({
            templateUrl:'modal.html',
            controller: 'modalCtrl',
            controllerAs: 'modalCtrl'
          });
          modalInstance.result['finally'](function() {
            modalInstance = null;
            if(endsWith($state.$current.name, ".generalModal")) {
              $state.go('^');
            }
          });
        };

      // definition of the onExit
      var onExit = function($state) { 
          console.log("Exiting state: " + $state.current.name)
          if (modalInstance) {
            modalInstance.close();
          }
      };

      // extend state with both of them
      state.self.onEnter = onEnter;
      state.self.onExit = onExit;

      return data;

    });
}])

我们扩展了名称为 endsWith ".generalModal" 的每个子状态 onExitonEnter .就这样。在一个地方...

实际查看 here

我也想解决这个问题。我终于解决了。

看我的Whosebug answer / question