controller - page - angular title
AngularJS: изменение хеша и маршрута без контроллера полной перезагрузки (7)
редактировать
Улучшенный подход при использовании 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
У меня есть контроллер с таким маршрутом:
# / статьи / 1234
Я хочу изменить маршрут без полной перезагрузки контроллера, поэтому я могу сохранить позицию других элементов в контроллере постоянной (списки, которые прокручиваются)
Я могу придумать несколько способов сделать это, но они все довольно уродливые. Есть ли лучший способ сделать что-то подобное? Я попытался поэкспериментировать с reloadOnSearch: false, но он ничего не меняет.
Краткий ответ:
Вы можете использовать метод $location.search()
как вы упомянули. Вы должны прослушивать событие "$routeUpdate"
в области видимости вместо других событий маршрута. $ route 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 .
Вы можете сделать это без хакеров $locationChange~
и HistoryState
используя опцию обещания resolve
route
.
Предполагая, что у вас был маршрут 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;
}]
}
}
);
Если бы тот же самый вызов,
Нашел взлом в другом ответе , который сделал трюк
Довольно чистое решение - все, что я сделал, это добавить эти строки в контроллер, который устанавливает $ location.path:
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
$route.current = lastRoute;
});
.. и убедился, что $ route введен в контроллер, конечно.
Но все же, похоже, что «DoNotFollowRoutesOnPathChange» - недостающая функция в AngularJS.
/ Jens
Обновление: поскольку прослушивание этого события эффективно убивает дальнейшее использование конфигураций $ routeProvider, мне пришлось ограничивать этот catch только текущим путем:
var lastRoute = $route.current;
if ($route.current.$route.templateUrl.indexOf('mycurrentpath') > 0) {
$route.current = lastRoute;
}
Как уродливо ...
Если вы установите для reloadOnSearch значение false, вы можете установить параметр ?a=b&c=d
URL-адреса без перезагрузки. Однако вы не можете изменить фактическое местоположение, но без перезагрузки.
Использование:
$routeProvider.when('/somewhere', {
controller: 'SomeCtrl',
reloadOnSearch: false
})
Это предотвратит перезагрузку контроллера при изменении параметра запроса, но также и при изменении хеша.
определите фабрику, чтобы обрабатывать window.history HTML5 так (обратите внимание, что я сохраняю собственный Stack, чтобы он работал на 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 Team намеревалась это сделать. Если вы хотите направить вперед / назад кнопку на своей модели, попробуйте сделать это с помощью окна HTML5. История
Надеюсь, я смогу помочь. Приветствия, Генрих