Подтвердить что ты не робот

AngularJS: изменение хеша и маршрута без контроллера полной перезагрузки

У меня есть контроллер с таким маршрутом:

#/статьи/1234

Я хочу изменить маршрут без полной перезагрузки контроллера, поэтому я могу сохранить положение другого элемента в постоянной контроллере (списки, которые прокручиваются)

Я могу придумать несколько способов сделать это, но они все довольно уродливые. Есть ли лучший способ сделать что-то подобное? Я попытался поэкспериментировать с reloadOnSearch: false, но он ничего не меняет.

4b9b3361

Ответ 1

Имел тот же самый вызов,

Найден взломать fooobar.com/questions/139644/..., который сделал трюк

Довольно чистое решение - все, что я сделал, это добавить эти строки в контроллер, который устанавливает $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;         
    }

Получение уродливого...

Ответ 2

Краткий ответ:

Вы можете использовать метод $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.

Ответ 3

Если вы установите для reloadOnSearch значение false, вы можете установить ?a=b&c=d часть URL без перезагрузки. Вы не можете изменить фактическое местоположение красиво, но без перезагрузки.

Ответ 4

редактировать

Улучшенный подход при использовании 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

Ответ 5

определите factory для обработки окна 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 планировала это так или иначе. Если вы хотите направить вперед/назад кнопку на своей модели, попробуйте сделать это с помощью HTML5 window.history

Надеюсь, что смогу помочь. Приветствия, Генрих

Ответ 6

Использование:

$routeProvider.when('/somewhere', {
    controller: 'SomeCtrl',
    reloadOnSearch: false
})

Это предотвратит перезагрузку контроллера при изменении параметра запроса, но также и при изменении хэша.

Ответ 7

Если вы приземлитесь здесь в 2015 году: реальный ответ здесь заключается в том, чтобы использовать ни один из этих хаков (я смею называть их так, потому что, используя любой из перечисленных выше методов, вы потеряете возможность использовать решение и подобные), но для перехода на ui-router.

Вот удобная презентация о различиях. Реализация должна быть такой же простой, как обмен $route для $state и преобразование состояний в имена.

В настоящее время я перехожу к методу, где я буду ссылаться на href на маршрут, с необязательным параметром get, который изменяет состояние без перезагрузки. Подробнее об этом см. Раздел здесь

Ответ 8

Это простое решение (неожиданно) работает для меня:

$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 (я знаю это старый).

Ответ 10

Вы можете сделать это без использования тэгов $locationChange~ и HistoryState, используя 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;
            }]
        }
    }
);