我需要在我的Angular应用程序中显示一个模态窗口(基本上只是一个隐藏的div,它将加载一个已编译的模板)。问题是,我需要在模态打开时更改URL,以便用户可以复制链接并直接进入模态窗口,并使用后退按钮关闭模态窗口并返回上一页。这类似于Pinterest单击图钉时处理模态窗口的方式。
到目前为止,我已经创建了一个加载模板的指令,使用$ compile编译它,注入$ scope然后显示已编译的模板。这很好用。
问题是,只要我使用$ location更改路径,路由控制器就会触发并将模板加载到ng-view中。
我想到了克服这个问题的两种方法,但还没有实现:
当我使用$ location更改网址时,以某种方式阻止路由控制器触发。我已经为$ routeChangeStart添加了一个监听器,以防止发生默认值,但这似乎不起作用。
以某种方式向页面添加另一个视图处理程序(在页面上基本上有2个命名的ng-view指令),并且每个都能够处理不同的路由。目前看不到Angular支持这一点。
网址必须是/ item / item_id,而不是/ item?item_id = 12345。
任何帮助都将不胜感激。
答案 0 :(得分:13)
如果您使用此处所述的ui.router模块,您现在可以执行此操作:https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-open-a-dialogmodal-at-a-certain-state。
他们的例子:
$stateProvider.state("items.add", {
url: "/add",
onEnter: function($stateParams, $state, $modal, $resource) {
$modal.open({
templateUrl: "items/add",
resolve: {
item: function() { new Item(123).get(); }
},
controller: ['$scope', 'item', function($scope, item) {
$scope.dismiss = function() {
$scope.$dismiss();
};
$scope.save = function() {
item.update().then(function() {
$scope.$close(true);
});
};
}]
}).result.then(function(result) {
if (result) {
return $state.transitionTo("items");
}
});
}
});
我还将'errorCallback'函数传递给then()函数,通过按Escape或单击背景来处理模态解除。
答案 1 :(得分:7)
我有类似的要求。我需要:
我找不到所有这些合作的好例子,但我能找到点点滴滴的例子,所以我把它们全部放在一个工作的例子中如下:
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.0/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.11/angular-ui-router.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.2/ui-bootstrap-tpls.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.css" rel="stylesheet">
<script>
// init the app with ui.router and ui.bootstrap modules
var app = angular.module('app', ['ui.router', 'ui.bootstrap']);
// make back button handle closing the modal
app.run(['$rootScope', '$modalStack',
function($rootScope, $modalStack) {
$rootScope.$on('$stateChangeStart', function() {
var top = $modalStack.getTop();
if (top) {
$modalStack.dismiss(top.key);
}
});
}
]);
// configure the stateProvider
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// default page to be "/" (home)
$urlRouterProvider.otherwise('/');
// configure the route states
$stateProvider
// define home route "/"
.state('home', {
url: '/'
})
// define modal route "/modal"
.state('modal', {
url: '/modal',
// trigger the modal to open when this route is active
onEnter: ['$stateParams', '$state', '$modal',
function($stateParams, $state, $modal) {
$modal
// handle modal open
.open({
template: '<div class="modal-header"><h3 class="modal-title">Modal</h3></div><div class="modal-body">The modal body...</div><div class="modal-footer"><button class="btn btn-primary" ng-click="ok()">OK</button><button class="btn btn-warning" ng-click="cancel()">Cancel</button></div>',
controller: ['$scope',
function($scope) {
// handle after clicking Cancel button
$scope.cancel = function() {
$scope.$dismiss();
};
// close modal after clicking OK button
$scope.ok = function() {
$scope.$close(true);
};
}
]
})
// change route after modal result
.result.then(function() {
// change route after clicking OK button
$state.transitionTo('home');
}, function() {
// change route after clicking Cancel button or clicking background
$state.transitionTo('home');
});
}
]
});
}
]);
</script>
</head>
<body>
<a href="#/modal" class="btn btn-default">POPUP!</a>
<div ui-view></div>
</body>
</html>
您可以在plunker中查看它: http://plnkr.co/edit/tLyfRP6sx9C9Vee7pOfC
单击plunker中的“打开嵌入视图”链接以查看哈希标记的工作情况。
答案 2 :(得分:5)
hermanschutte的解决方案有效(见comment on Tiago Roldão's post)。我正在逐步发布以帮助澄清。
首先,在配置中:
.when('/posts', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
reloadOnSearch: false // this allows us to use the back button to get out of modals.
})
然后,在打开模态(你需要位置模块):
$location.search('modal');
在模态控制器中:
$scope.$on('$locationChangeSuccess', function() {
$scope.close(); // call your close function
});
答案 3 :(得分:2)
您提到的命名视图解决方案已经对angularJS邮件列表进行了很好的讨论,但截至目前(以及接近中期),$ route系统无法处理多个视图。
正如我在一些地方所说的那样,在这里也有几次,$ route系统是角度非常自以为是的立场可能成为障碍的情况之一:它意味着简单,但它不是非常可配置。我个人不直接使用它,而是通过我找到here的解决方案绕过它。
它使事情变得复杂,但它给你更大的灵活性 - 这个想法是$ route只用于触发(手动)渲染功能,你可以在其中分配值并触发$ broadcasts(通常,来自主控制器)。
我还没有尝试的一件事是“混合”解决方案 - 即正常使用$ route系统,并将/ item / item_id路由配置为NOT没有视图参数(以便不更改主视图,由其他路由发起)并通过$ routeChangeStart事件做一些事情(记住你可以为路由分配任何值,正如你所引用的页面所见)
同样,我个人更喜欢完全使用替代方法。
答案 4 :(得分:2)
您可能想尝试获取AngularJS源代码,调整并加载自己的$ route和$ routeProvider,然后将它们注入Angular本机。
您可能只需要添加一个标志来拦截路线更改的触发器。
另一个更简单的选择是挂钩事件系统,使用$scope.$on(event_name, function callback(ev) {...})
并在传入事件上调用.preventDefault()
,希望它将停止内部$ route触发器。定位系统广播$locationChangeStart
事件,并在产生defaultPrevented
事件之前检查$locationChangeSuccess
属性。
不要忘记发布结果!