你能在AngularJS中不重新加载控制器的情况下更改路径吗?
你能在AngularJS中不重新加载控制器的情况下更改路径吗?
这个问题之前已经问过了,从答案来看情况不太乐观。我想在考虑这个示例代码的基础上再次提问...\n我的应用程序在提供服务的同时加载当前项。有几个控制器可以操作项的数据,而无需重新加载项。\n如果项尚未设置,我的控制器将重新加载该项,否则将在控制器之间使用当前加载的项。\n问题:我想为每个控制器使用不同的路径,而不重新加载Item.html。\n1)这可能吗?\n2)如果不可能,有没有更好的方法来实现每个控制器的路径,而不像我在这里想出的那样重新加载?\napp.js\n
var app = angular.module('myModule', []). config(['$routeProvider', function($routeProvider) { $routeProvider. when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}). when('/items/:itemId/foo', {templateUrl: 'partials/item.html', controller: ItemFooCtrl}). when('/items/:itemId/bar', {templateUrl: 'partials/item.html', controller: ItemBarCtrl}). otherwise({redirectTo: '/items'}); }]);
\nItem.html\n
Foo Bar
\ncontroller.js\n
// 用于加载$scope.item的辅助函数,如果是刷新或直接链接 function itemCtrlInit($scope, $routeParams, MyService) { $scope.item = MyService.currentItem; if (!$scope.item) { MyService.currentItem = MyService.get({itemId: $routeParams.itemId}); $scope.item = MyService.currentItem; } } function itemFooCtrl($scope, $routeParams, MyService) { $scope.view = {name: 'foo', template: 'partials/itemFoo.html'}; itemCtrlInit($scope, $routeParams, MyService); } function itemBarCtrl($scope, $routeParams, MyService) { $scope.view = {name: 'bar', template: 'partials/itemBar.html'}; itemCtrlInit($scope, $routeParams, MyService); }
\n解决方案。\n状态:根据接受的答案中建议的使用搜索查询的方法,我能够在不重新加载主控制器的情况下提供不同的URL。\napp.js\n
var app = angular.module('myModule', []). config(['$routeProvider', function($routeProvider) { $routeProvider. when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}). when('/item/:itemId/', {templateUrl: 'partials/item.html', controller: ItemCtrl, reloadOnSearch: false}). otherwise({redirectTo: '/items'}); }]);
\nItem.html\n
\ncontroller.js\n
function ItemCtrl($scope, $routeParams, Appts) { $scope.views = { foo: {name: 'foo', template: 'partials/itemFoo.html'}, bar: {name: 'bar', template: 'partials/itemBar.html'}, } $scope.view = $scope.views[$routeParams.view]; }
\ndirectives.js\n
app.directive('itemTab', function(){ return function(scope, elem, attrs) { scope.$watch(attrs.itemTab, function(val) { if (val+'Tab' == attrs.id) { elem.addClass('active'); } else { elem.removeClass('active'); } }); } });
\n我的partials中的内容被包裹在ng-controller=...
中。
问题的出现原因是在AngularJS中改变路径时会重新加载控制器,而有些情况下我们不希望重新加载控制器。解决方法是将ng-controller指令放在更高一级的元素上,并且在路由中不设置控制器。这样可以避免控制器的重新加载。另外,如果需要在控制器中读取$routeParams的值,可以在$routeChangeSuccess事件处理程序中进行读取。下面是一个示例代码:
<body ng-controller="ProjectController"> <div ng-view><div>
.when('/', { templateUrl: "abc.html" })
通过上述方法可以实现在改变路径时不重新加载控制器,同时能够读取$routeParams的值。这是一种解决该问题的有效方法。
在AngularJS中,当我们需要更改路径而不重新加载控制器时,可以使用以下方法:
在应用程序文件的.config之后添加以下内容:
app.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) { var original = $location.path; $location.path = function (path, reload) { if (reload === false) { var lastRoute = $route.current; var un = $rootScope.$on('$locationChangeSuccess', function () { $route.current = lastRoute; un(); }); } return original.apply($location, [path]); }; }])
这个方法的原理是,当设置reload参数为false时,它会在$locationChangeSuccess事件中将$route.current设置回上一个路由,从而实现改变路径而不重新加载控制器的效果。
这个方法的来源是https://www.consolelog.io/angularjs-change-path-without-reloading,这是我找到的最优雅的解决方法。
不过需要注意的是,这个解决方法会保留旧的路由,如果你请求$route.current,你会得到之前的路径,而不是当前的路径。但是总体来说,这是一个非常好的技巧。
某些情况下是否有办法让浏览器的后退按钮“遵循”这个方法,但是没有给出具体的解决方案。
还某些情况下,这个方法仍然会重新加载视图。
还某些情况下,使用这个方法后,有些$scope变量在路由改变后无法使用,所以需要重新创建所有的对象和变量。
也有人问是否可以在ui-router中实现相同的功能,但是没有给出具体的解决方案。
有人分享了自己的解决方案,并补充了一些之前方法中没有的内容。
这个方法在AngularJS 1.5中运行良好。
总结一下,这个问题的出现是因为在AngularJS中更改路径时会重新加载控制器,而解决方法是通过修改$location.path的方式来实现改变路径而不重新加载控制器。
在AngularJS中,有时我们希望在不重新加载控制器的情况下更改路径。一个用户在论坛上提问了这个问题,他的需求是将路径中的#/item/{{item.id}}/foo
和#/item/{{item.id}}/bar
改为#/item/{{item.id}}/?foo
和#/item/{{item.id}}/?bar
。有人回答说,可以在/item/{{item.id}}/
的路由上设置reloadOnSearch
属性为false
,这样当url的搜索部分发生变化时,AngularJS就不会重新加载视图。
另一个用户回答说,你可以在itemCtrlInit
中创建一个对$location.search()
进行监视的方法,并根据搜索参数的不同更新$scope.view.template
。然后,可以用<div ng-controller="itemFooCtrl">... your template content...</div>
来包装这些模板。该用户还建议用户将问题的解决方案更新到问题中,以便其他人也可以获得帮助。
原问题提问者表示,他会在解决问题后将解决方案更新到问题中。他还提到了自己遇到的作用域问题,并表示会在稍后解决。另一个用户提醒他可以使用jsFiddle/plnkr等工具来创建多个片段。原问题提问者表示感谢,并表示这些回答确实指导了他正确的方向。
最后,有人指出其实不需要重新格式化URL,因为AngularJS的文档中已经提到了reloadOnSearch
参数可以实现在搜索参数变化时重新加载路由。还某些情况下在UI Router中也存在相同的参数。
这个讨论中还有其他一些用户的回答和问题,但与原问题的解决方案无关。这个讨论给出了在AngularJS中如何在不重新加载控制器的情况下更改路径的解决方法。