Angular-ui.router:在不刷新视图的情况下更新URL。
Angular-ui.router:在不刷新视图的情况下更新URL。
我有一个Angular SPA,它基于餐厅数据的不同切分,提供了各种推荐列表和Google地图位置(请参见m.amsterdamfoodie.nl)。我希望每个列表都有自己的URL。为了让Google爬取不同的列表,我使用了标签作为离屏导航。\n目前
标签会导致视图刷新,而地图上的刷新非常明显。\n
- \n
- 我可以使用
ng-click
和$event.preventDefault()
来阻止这种情况发生(请参见下面的代码片段),但接下来我需要实现一种更新浏览器URL的方法。 - 但是,尝试使用Angular的
$state
或浏览器的history.pushstate
时,我会触发状态变化和视图刷新...!
\n
\n
\n因此,我的问题是如何更新模型和URL,但不刷新视图?(另请参见Angular/UI-Router - How Can I Update The URL Without Refreshing Everything?)\n我尝试了很多方法,目前有以下HTML代码:\n
Budget
\n在控制器中:\n
this.action = ($event) -> $event.preventDefault() params = $event.target.href.match(/criteria\/(.*)\/(.*)$/) # 似乎会导致视图刷新 # history.pushState({}, "page 2", "criteria/"+params[1]+"/"+params[2]); # 似乎会导致视图刷新 # $state.transitionTo 'criteria', {criteria:params[1], q:params[2]}, {inherit:false} updateModel(...)
\n我认为正在发生的事情是,我正在触发$stateProvider
的代码:\n
angular.module 'afmnewApp' .config ($stateProvider) -> $stateProvider .state 'main', url: '/' templateUrl: 'app/main/main.html' controller: 'MainCtrl' controllerAs: 'main' .state 'criteria', url: '/criteria/:criteria/:q' templateUrl: 'app/main/main.html' controller: 'MainCtrl' controllerAs: 'main'
\n可能的一个线索是,如果我加载http://afmnew.herokuapp.com/criteria/cuisine/italian,则在导航时视图会刷新,而如果我加载http://afmnew.herokuapp.com/,则没有刷新,但也没有更新URL。我完全不明白为什么会发生这种情况。
Angular-ui.router: 在不刷新视图的情况下更新URL
问题的原因是如果子视图在父视图内部,两个控制器将共享相同的作用域。所以你可以在父视图中放置一个虚拟(或必要的)ui-view,该视图将由子视图填充。然后在父控制器中插入一个$scope.loadChildData = function(itemID){..blabla..};
方法,在子控制器加载时将调用该方法。因此,当用户点击<a ui-sref="childState({itemID: 12})">bla</a>
时,只有子控制器和子视图将被刷新。然后,您可以使用必要的参数调用父作用域函数。
解决方法是在一个没有与视图关联的控制器中使用div标签包装地图。不使用作用域继承,但是将所有关键数据保存在一个服务中,控制器可以随时访问。
Angular-ui.router: Update URL without view refresh问题的出现原因是想要在不刷新视图的情况下更新URL。解决方法是使用UI-Router。
根据之前的讨论,我们可以使用UI-Router来解决这个问题。下面给出了一个工作示例。如果这个示例不完全满足需求,请将其作为一些灵感。
所以,这里有一个状态定义(我们只有两个状态):
$stateProvider .state('main', { url: '/', views: { '@' : { templateUrl: 'tpl.layout.html', controller: 'MainCtrl', }, 'right' : { templateUrl: 'tpl.right.html',}, 'map' : { templateUrl: 'tpl.map.html', controller: 'MapCtrl', }, 'list' : { templateUrl: 'tpl.list.html', controller: 'ListCtrl', }, }, }) .state('main.criteria', { url: '^/criteria/:criteria/:value', views: { 'map' : { templateUrl: 'tpl.map.html', controller: 'MapCtrl', }, 'list' : { templateUrl: 'tpl.list.html', controller: 'ListCtrl', }, }, });
这是我们的主要`tpl.layout.html`:
我们可以看到,主状态会定位到主状态的嵌套视图,例如`'right'`。子视图`main.criteria`也会注入到`layout`视图中。它的URL以符号`^`开头,允许主路由有`/`,并且子路由没有重复的斜杠。
这里还有控制器,它们有点简单,但是它们应该显示出后台可以加载真实数据的情况(基于条件)。
最重要的是,父控制器`MainCtrl`创建了`$scope.Model = {}`。这个属性将(通过继承)在父控制器和子控制器之间共享。这就是为什么这一切会起作用的原因。
这应该给出一些关于如何使用UI-Router提供的功能的想法。
检查上述示例,[这里](http://plnkr.co/edit/iQUU6F?p=preview)是一个工作示例。
如果我们不想重新创建地图视图,我们可以从子状态定义中省略它:
.state('main.criteria', { url: '^/criteria/:criteria/:value', views: { //'map' : { // templateUrl: 'tpl.map.html', // controller: 'MapCtrl', //}, 'list' : { templateUrl: 'tpl.list.html', controller: 'ListCtrl', }, }, });
现在,地图视图只会接收模型中的更改(可以被监视),但是视图和控制器不会重新渲染。
另外,这里还有另一个使用`controllerAs`的示例,[点击这里](http://plnkr.co/edit/y0GzHv?p=preview)。
.state('main', { url: '/', views: { '@' : { templateUrl: 'tpl.layout.html', controller: 'MainCtrl', controllerAs: 'main', }, ... }, }) .state('main.criteria', { url: '^/criteria/:criteria/:value', views: { 'list' : { templateUrl: 'tpl.list.html', controller: 'ListCtrl', controllerAs: 'list', }, }, });
最后,这里还有一个[链接](http://plnkr.co/edit/y0GzHv?p=preview)。
快速问题:在MainCtrl中创建Model是否重要?到目前为止,我一直使用一个共享的Factory。
请原谅之前的问题。我的主要兴趣不是刷新地图,而是在模型更改时让控制器删除和重新创建标记(通过在'right'面板上单击引起)。我修改了你的plnkr示例,并在每次加载MapCtrl时添加了一个console.log消息,这相当于视图重新加载(我认为),但它一直在进行。这让我有些担心,但可能是因为我将模型保存在一个Factory中(我在上面的评论中提到过)。
我稍后会给你答复,我保证。
我目前正在考虑将地图本身放入主视图中,但是通过子视图创建标记。
问题原因:在使用Angular-ui.router进行页面跳转时,虽然可以通过$state.go方法实现URL的更新,但是在使用浏览器的前进和后退功能时,页面会重新加载。
解决方法:通过设置$state.go方法的第三个参数,将notify和reload属性设置为false,即可实现URL的更新而不刷新页面。
整理后的文章如下:
Angular-ui.router: 更新URL而不刷新视图的解决方法
在使用Angular-ui.router进行页面跳转时,我们经常需要更新URL来保持页面的状态。然而,使用$state.go方法更新URL会导致页面重新加载,这在某些情况下可能会带来一些问题。
解决这个问题的方法是设置$state.go方法的第三个参数,将notify和reload属性设置为false。这样,在使用$state.go方法更新URL时,页面不会重新加载。
下面是一个示例代码:
$state.go('my.state', {id:data.id}, {notify:false, reload:false}); //And to remove the id from the url: $state.go('my.state', {id:undefined}, {notify:false, reload:false});
这段代码中,我们使用$state.go方法更新URL,同时将notify和reload属性设置为false,以实现URL的更新而不刷新页面。
需要注意的是,这个解决方法只适用于angular-ui-router版本为0.2.18及以上的情况。如果你使用的是旧版本的angular-ui-router,可能需要升级到0.2.18以上的版本才能使用这个解决方法。
更多关于$state API的信息,可以查看http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state。
通过设置$state.go方法的第三个参数,将notify和reload属性设置为false,可以实现在更新URL时不刷新页面。这个解决方法适用于angular-ui-router版本为0.2.18及以上的情况。
然而,需要注意的是,在一些特定情况下,仍然可能会存在一些与这个问题相关的次要问题。如果你遇到了这些问题,可以参考相关的github讨论,或者查看最新版本的UI-Router文档,以获取更多信息和解决方案。