使用ui-router和Bootstrap-ui模态



我知道这已经讨论过很多次了,大多数文章都引用了这段代码:AngularJS中带有自定义URL的模态窗口

但我就是不明白。我觉得这一点都不清楚。我还发现这个jsfiddle实际上是伟大的,非常有用,除了它不添加url,并允许我使用后退按钮来关闭模态。


编辑:这就是我需要帮助的。

所以让我试着解释一下我想要达到的目的。我有一个表单来添加一个新项目,我有一个链接'添加新项目'。我想当我点击"添加新项目"一个模态弹出的形式,我已经创建了"add-item.html"。这是一个新的状态,所以url更改为/add-item。我可以填写表格,然后选择保存或关闭。关闭,关闭模态:p(多奇怪啊)。但我也可以点击返回关闭模态,并返回到上一页(状态)。 此时我不需要Close的帮助,因为我仍然在努力实际获得模态工作。


这是我的代码:

导航控制器:(这是放置模态函数的正确位置吗?)

angular.module('cbuiRouterApp')
  .controller('NavbarCtrl', function ($scope, $location, Auth, $modal) {
    $scope.menu = [{
      'title': 'Home',
      'link': '/'
    }];
    $scope.open = function(){
        // open modal whithout changing url
        $modal.open({
          templateUrl: 'components/new-item/new-item.html'
        });
        // I need to open popup via $state.go or something like this
        $scope.close = function(result){
          $modal.close(result);
        };
      };
    $scope.isCollapsed = true;
    $scope.isLoggedIn = Auth.isLoggedIn;
    $scope.isAdmin = Auth.isAdmin;
    $scope.getCurrentUser = Auth.getCurrentUser;
    $scope.logout = function() {
      Auth.logout();
      $location.path('/login');
    };
    $scope.isActive = function(route) {
      return route === $location.path();
    };
  });

我是这样激活情态的:

 <li ng-show='isLoggedIn()' ng-class='{active: isActive("/new-item")}'>
   <a href='javascript: void 0;' ng-click='open()'>New Item</a>
 </li>

new-item.html:

<div class="modal-header">
  <h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
  <ul>
    <li ng-repeat="item in items"><a ng-click="selected.item = item">{{ item }}</a></li>
  </ul>Selected:<b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
  <button ng-click="ok()" class="btn btn-primary">OK</button>
  <button ng-click="close()" class="btn btn-primary">OK</button>
</div>

另外,虽然这打开了一个模态,但它并没有关闭它,因为我无法解决这个问题。

将模态视为状态的视图组件是很直观的。用一个带有视图模板、一个控制器和一些解析器的状态定义。这些特性中的每一个也适用于模态的定义。更进一步,将状态进入链接到打开模态,将状态退出链接到关闭模态,如果你可以封装所有的管道,那么你就有了一种机制,可以像使用ui-sref$state.go作为进入状态,使用后退按钮或更多特定于模态的触发器作为退出一样使用。

我已经相当广泛地研究了这一点,我的方法是创建一个模态状态提供程序,可以在配置模块来定义绑定到模态的状态时类似地使用$stateProvider。当时,我特别感兴趣的是通过状态和模态事件统一控制模态解除,这比你所要求的要复杂得多,所以这里有一个简化的例子。

关键是使模态成为状态的责任,并使用模态提供的钩子来保持状态与模态通过作用域或其UI支持的独立交互同步。

.provider('modalState', function($stateProvider) {
    var provider = this;
    this.$get = function() {
        return provider;
    }
    this.state = function(stateName, options) {
        var modalInstance;
        $stateProvider.state(stateName, {
            url: options.url,
            onEnter: function($modal, $state) {
                modalInstance = $modal.open(options);
                modalInstance.result['finally'](function() {
                    modalInstance = null;
                    if ($state.$current.name === stateName) {
                        $state.go('^');
                    }
                });
            },
            onExit: function() {
                if (modalInstance) {
                    modalInstance.close();
                }
            }
        });
    };
})

状态项启动模态。状态退出关闭它。模态可能会自己关闭(例如:通过背景点击),所以你必须观察并更新状态。

这种方法的好处是你的应用程序继续主要与状态和状态相关的概念进行交互。如果您以后决定将模态转换为常规视图,或者相反,那么只需更改很少的代码。

这是一个通过将resolve部分传递到controller来改进@nathan-williams解决方案的provider:

.provider('modalState', ['$stateProvider', function($stateProvider) {
  var provider = this;
  this.$get = function() {
    return provider;
  }
  this.state = function(stateName, options) {
    var modalInstance;
    options.onEnter = onEnter;
    options.onExit = onExit;
    if (!options.resolve) options.resolve = [];
    var resolveKeys = angular.isArray(options.resolve) ? options.resolve : Object.keys(options.resolve);
    $stateProvider.state(stateName, omit(options, ['template', 'templateUrl', 'controller', 'controllerAs']));
    onEnter.$inject = ['$uibModal', '$state', '$timeout'].concat(resolveKeys);
    function onEnter($modal, $state, $timeout) {
      options.resolve = {};
      for (var i = onEnter.$inject.length - resolveKeys.length; i < onEnter.$inject.length; i++) {
        (function(key, val) {
          options.resolve[key] = function() { return val }
        })(onEnter.$inject[i], arguments[i]);
      }
      $timeout(function() { // to let populate $stateParams
        modalInstance = $modal.open(options);
        modalInstance.result.finally(function() {
          $timeout(function() { // to let populate $state.$current
            if ($state.$current.name === stateName)
              $state.go(options.parent || '^');
          });
        });
      });
    }
    function onExit() {
      if (modalInstance)
        modalInstance.close();
    }
    return provider;
  }
}]);
function omit(object, forbidenKeys) {
  var prunedObject = {};
  for (var key in object)
    if (forbidenKeys.indexOf(key) === -1)
      prunedObject[key] = object[key];
  return prunedObject;
}

然后像这样使用:

.config(['modalStateProvider', function(modalStateProvider) {
  modalStateProvider
    .state('...', {
      url: '...',
      templateUrl: '...',
      controller: '...',
      resolve: {
        ...
      }
    })
}]);

我回答了一个类似的问题,并在这里提供了一个例子:

AngularJS中带自定义URL的模态窗口

有一个完整的工作HTML和一个链接到plunker。

$modal本身没有close()函数,我的意思是如果你打开console.log($modal),你可以看到只有一个open()函数。

关闭模态依赖于$modalInstance对象,你可以在你的modalController中使用。

So This: $modal.close(result)实际上不是一个函数!

注意:console.log(模态);==>> result:

          Object { open: a.$get</k.open() }
           // see ? just open ! , no close !

有一种方法可以解决这个问题,一种方法是:

首先你必须像这样在你的模态中定义一个控制器:

   $modal.open({
      templateUrl: 'components/new-item/new-item.html',
      controller:"MyModalController"
    });

然后,后来,

    app.controller('MyModalController',function($scope,$modalInstance){
      $scope.closeMyModal = function(){
       $modalInstance.close(result);
        }
       // Notice that, This $scope is a seperate scope from your NavbarCtrl,
       // If you want to have that scope here you must resolve it
   });

最新更新