我有一个控制器,路线如下:
#/articles/1234
我想在不完全重新加载控制器的情况下更改路线,所以我可以保持控制器中其他东西的位置不变(滚动的列表)
我可以想到几种方法来做到这一点,但它们都很丑陋。有没有做这样的事情的最佳实践?我尝试尝试使用 reloadOnSearch: false,但它似乎并没有改变任何东西。
我有一个控制器,路线如下:
#/articles/1234
我想在不完全重新加载控制器的情况下更改路线,所以我可以保持控制器中其他东西的位置不变(滚动的列表)
我可以想到几种方法来做到这一点,但它们都很丑陋。有没有做这样的事情的最佳实践?我尝试尝试使用 reloadOnSearch: false,但它似乎并没有改变任何东西。
有同样的挑战,
在另一个 StackOverflow 响应中发现了一个可以解决问题的 hack
相当干净的解决方案 - 我所做的只是将这些行添加到设置 $location.path 的控制器中:
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
$route.current = lastRoute;
});
..并确保将 $route 注入到控制器中。
但是,感觉就像“DoNotFollowRoutesOnPathChange”是AngularJS中缺少的功能。
/詹斯
更新:由于监听此事件有效地杀死了 $routeProvider 配置的进一步使用,我不得不将此捕获限制为仅当前路径:
var lastRoute = $route.current;
if ($route.current.$route.templateUrl.indexOf('mycurrentpath') > 0) {
$route.current = lastRoute;
}
变丑了...
您可以使用$location.search()
您提到的方法。您应该在范围内收听"$routeUpdate"
事件,而不是其他路由事件。$路由 API。
首先(您已经知道),添加reloadOnSearch: false
到您的$routeProvider
:
$routeProvider.when('/somewhere', {
controller: 'SomeCtrl',
reloadOnSearch: false
})
如果路径部分 ( ) 与当前位置不同,则更改您的锚标记href
或这将触发事件。否则会触发事件。ng-href
href="#/somewhere?param=value"
$routeChangeSuccess
/somewhere
$routeUpdate
监听范围内的事件:
$scope.$on("$routeUpdate", function(event, route) {
// some code here
});
如果要更改代码中的搜索参数,可以使用$location.search()
方法。$location.search API。
如果将 reloadOnSearch 设置为 false,则可以设置?a=b&c=d
不重新加载的 url 部分。但是,如果不重新加载,您将无法漂亮地更改实际位置。
使用 ngRoute 时更好的方法:
/**
* Add skipReload() to $location service.
*
* See https://github.com/angular/angular.js/issues/1699
*/
app.factory('location',
['$rootScope', '$route', '$location',
function($rootScope, $route, $location) {
$location.skipReload = function() {
var lastRoute = $route.current;
var deregister = $rootScope.$on('$locationChangeSuccess',
function(e, absUrl, oldUrl) {
console.log('location.skipReload', 'absUrl:', absUrl, 'oldUrl:', oldUrl);
$route.current = lastRoute;
deregister();
});
return $location;
};
return $location;
}]);
如何使用:
app.controller('MyCtrl', ['$scope', 'location', function($scope, location) {
$scope.submit = function() {
location.skipReload().path(path);
};
}]);
我根据 Jens X Augustsson 的回答写了一个可重用的工厂:
app.factory('DoNotReloadCurrentTemplate', ['$route', function($route) {
return function(scope) {
var lastRoute = $route.current;
scope.$on('$locationChangeSuccess', function() {
if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
console.log('DoNotReloadCurrentTemplate',
$route.current.$$route.templateUrl);
$route.current = lastRoute;
}
});
};
}]);
适用于 AngularJS 1.0.6
如何使用:
app.controller('MyCtrl',
['$scope', 'DoNotReloadCurrentTemplate',
function($scope, DoNotReloadCurrentTemplate) {
DoNotReloadCurrentTemplate($scope);
}]);
AngularJS 问题在这里:https ://github.com/angular/angular.js/issues/1699
定义一个工厂来处理 HTML5 的 window.history 像这样(注意我保留了一个自己的堆栈以使其在 android 上也能工作,因为它在那里有一些问题):
.factory('History', function($rootScope) {
var StateQueue = [];
var StatePointer = 0;
var State = undefined;
window.onpopstate = function(){
// called when back button is pressed
State = StateQueue.pop();
State = (State)?State:{};
StatePointer = (StatePointer)?StatePointer-1:0;
$rootScope.$broadcast('historyStateChanged', State);
window.onpopstate = window.onpopstate;
}
return {
replaceState : function(data, title, url) {
// replace current state
var State = this.state();
State = {state : data};
window.history.replaceState(State,title,url);
StateQueue[StatePointer] = State;
$rootScope.$broadcast('historyStateChanged', this.state());
},
pushState : function(data, title, url){
// push state and increase pointer
var State = this.state();
State = {state : data};
window.history.pushState(State,title,url);
StateQueue.push(State);
$rootScope.$broadcast('historyStateChanged', this.state());
StatePointer ++;
},
fakePush : function(data, title, url) {
// call this when you do location.url(url)
StateQueue.push((StateQueue.length - 1 >= 0)?StateQueue[StateQueue.length -1]:{});
StatePointer ++;
$rootScope.$broadcast('historyStateChanged', this.state());
},
state : function() {
// get current state
return (StateQueue[StatePointer])?StateQueue[StatePointer]:{};
},
popState : function(data) {
// TODO manually popState
},
back : function(data) {
// TODO needed for iphone support since iphone doesnt have a back button
}
}
})
在您的依赖范围上添加一些侦听器,您会像这样:
$scope.$on('historyStateChanged', function(e,v) {
if(v)
$scope.state = v;
else
$scope.state = {}
});
我就是这样做的。在我看来,URL 只应在加载新视图时更改。我认为这就是 Angular 团队的意图。如果您想在模型上映射前进/后退按钮,请尝试使用 HTML5 的 window.history
希望我能帮上忙。干杯,海因里希
利用:
$routeProvider.when('/somewhere', {
controller: 'SomeCtrl',
reloadOnSearch: false
})
这将防止在查询参数更改以及哈希更改时重新加载控制器。
这个简单的解决方案(令人惊讶)对我有用:
$state.params.id = id; //updating the $state.params somehow prevents reloading the state
$location.path('/articles/' + id);
它不会阻止状态重新加载后退和前进按钮。注意:我使用的是 angularjs 1.2.7 和 ui-router 0.0.1(我知道它很旧)。
您可以使用s promise 选项在没有$locationChange~
and HistoryState
hacks的情况下执行此操作。route
resolve
假设您有一条article
路线,其中该号码发生了变化,您可以这样做;
$routeProvider.when(
'/article/:number',
{
templateUrl : 'partial.html',
controller : 'ArticleCtrl',
resolve : {
load : ['$q', '$routeParams', function($q, $routeParams) {
var defer = $q.defer();
//number was specified in the previous route parameters, means we were already on the article page
if ($routeParams.number)
//so dont reload the view
defer.reject('');
//otherwise, the number argument was missing, we came to this location from another route, load the view
else
defer.resolve();
return defer.promise;
}]
}
}
);