30

我知道这已经覆盖了很多次,最条款提及这段代码:Modal window with custom URL in AngularJS使用UI路由器与引导的UI模式

但是我就是不明白这一点。我根本没有发现这一点非常清楚。我也发现这jsfiddle这实际上是伟大的,非常有帮助,除了这不添加网址,并允许我使用后退按钮关闭模式。


编辑:这是我需要帮助。

因此,让我尝试解释我想达到的目标。我有一个表单来添加一个新项目,我有一个链接'添加新项目'。我希望当我点击“添加新项目”时,会弹出一个模式,其中包含我创建的“add-item.html”表单。这是一个新的状态,因此url更改为/ add-item。 我可以填写表格,然后选择保存或关闭。关闭,关闭模态:p(奇怪)。但是我也可以点击返回以关闭模式,并返回到前一页(状态)。 在这一点上,我不需要帮助关闭,因为我仍然在努力实现模态工作。


这是我的代码,因为它代表:

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

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> 

新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> 

而且同时这确实打开一个模式不会关闭它,因为我不能工作了这一点。

+0

您能够关闭你的情态点击关闭时窗口?我觉得不是。对? – micronyks

+0

不,我无法完成它。我只能打开它,即使这样,它不仅不会关闭,但它不会与状态和网址更改,所以像活动链接这样的东西将无法正常工作。 – Daimz

+0

我用最近的尝试来解决这个问题,但是它不起作用。 http://plnkr.co/edit/k514Nc25zfr0amtnxXDu?p=preview – Daimz

回答

51

将模态视为统计的视图组件很直观即采用视图模板,控制器和可能的一些解决方案进行状态定义。每个功能也适用于模态的定义。更进一步,将状态条目链接到打开模式和状态退出来关闭模式,如果你可以封装所有的管道,那么你有一个机制,可以像使用ui-sref$state.go的状态一样使用,后退按钮或更多模态特定的触发器退出。

我研究这个fairly extensively,我的方法是创建配置模块定义被绑定到模态状态时有可能类似用于$stateProvider模式状态供应商。当时,我特别感兴趣的是通过状态和模态事件来统一对模态解雇的控制,这比你要求的要复杂得多,所以这里是一个simplified example

关键是使模态成为状态的责任,并使用模态提供的挂钩来保持状态与独立交互的同步,模式通过范围或其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(); 
       } 
      } 
     }); 
    }; 
}) 

State entry启动模式。国家退出关闭它。模式可能会自行关闭(例如:通过背景点击),因此您必须观察并更新状态。

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

+0

这太有帮助了!非常感谢,而且这一切都是有道理的,甚至更好。我遇到了另一个问题。这工作,如果我在国家'主要',但如果我去另一个国家'关于'我得到这个'无法解决'.add'状态'about''我需要一种方法,让这个工作在任何顶部状态关于,主要,联系等,因为它可以从主导航访问。 – Daimz

+0

点前缀用于相对导航到子状态。如果add是一个about的兄弟,那么你需要一个像''^ .add'''这样的表达式来从about添加。查看[$ state.go]的文档(http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state#go)并查看是否这有助于。 –

+0

我已经读过,但我仍然无法正常工作。我分叉你的plnk并做了一些改变来说明我在做什么。 http://plnkr.co/edit/eupjB1i0djFGLcaGCD8j?p=preview也许我把'^'放在错误的地方,但我也尝试把它放在'$ state.go('^。add')'中,那也没有工作。 – Daimz

0

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

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

所以这个:$ modal.close(result)实际上并不是一个函数!

提示: console.log($ modal); == >>结果:

  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 

    }); 
+0

我上面说过,我尝试了一个新的方法来获得这个工作,如这个plunk http://plnkr.ed/edit/k514Nc25zfr0amtnxXDu?p =预览,但我提出这个方法的原因是该方法依赖于解决方案。我试着看看究竟是什么解决方案,但它没有意义,您是否介意阐述它是如何工作的,以及为什么我必须解决它以让NavbarCtrl在那里? – Daimz

+0

我仍然没有得到你的问题:( 1-你想知道什么是解决方案,它是如何工作的? 2-关闭模态是你的问题吗? – Milad

+0

@ xe4me,这是正确的。可以使用,如果你不想使用$ modalInstance。第二种方法是, var myModal = $ modal.open({templateUrl:'myHtml.html'}); myModal.close(); <-----当你点击关闭按钮时,这个方法也可以工作。 – micronyks

6

这里是一个provider通过向下传递resolve部分的controller提高@森 - 威廉姆斯的解决方案:

.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: { 
     ... 
     } 
    }) 
}]); 
+0

这是正确的解决方案。 – Damiox

+0

谢谢!这是正确的解决方案! –

+0

你可以看看http://stackoverflow.com/questions/40767450/how-to-use-angular-ui-router-with-angular-bootstrap-modal-uibmodal请 –