AngularJS $ location не меняет путь

126

У меня проблема с изменением URL-адреса страницы после отправки формы.

Вот как выглядит мое приложение:

  1. Установлены маршруты, распознается URL какой-то страницы формы.
  2. Страница загружается, контроллер устанавливает переменные, запускаются директивы.
  3. Запускается специальная директива формы, которая выполняет отправку специальной формы с использованием AJAX.
  4. После выполнения AJAX (Angular не заботится об AJAX) запускается обратный вызов, и директива вызывает $scope.onAfterSubmitфункцию, которая устанавливает местоположение.

Проблема в том, что после установки локации ничего не происходит. Я тоже пробовал установить параметр местоположения /... Нет. Я также пытался не отправлять форму. Ничего не работает.

Я проверил, достигает ли код onAfterSubmitфункции (что он делает).

Моя единственная мысль заключается в том, что каким-то образом изменилась область действия функции (поскольку она вызывается из директивы), но опять же, как она может вызывать, onAfterSubmitесли область видимости изменилась?

Вот мой код

var Ctrl = function($scope, $location, $http) {
  $http.get('/resources/' + $params.id + '/edit.json').success(function(data) {
    $scope.resource = data;
  });

  $scope.onAfterSubmit = function() {
    $location.path('/').replace();
  };
}
Ctrl.$inject = ['$scope','$location','$http'];

Кто-нибудь может мне помочь, пожалуйста?

Мацко
источник
1
возможный дубликат Angular $ location.path не работает
Джим Г.
Имейте в виду, что это было создано за год до этого.
matsko 06
Правильно и с преимуществом дополнительного года, у другого есть более точно правильный принятый ответ.
Джим Г.
1
@JimG. это не дубликат, этот вопрос задан 4 года назад, вопрос, который вы ссылаетесь, - 2 года назад.
Кастро Рой,

Ответы:

298

Несколько дней назад у меня была похожая проблема. В моем случае проблема заключалась в том, что я изменил что-то с помощью сторонней библиотеки (если быть точным, jQuery), и в этом случае, хотя функции вызова и установка переменных работают, Angular не всегда распознает, что есть изменения, поэтому он никогда не переваривает.

$ apply () используется для выполнения выражения в angular вне рамок angular. (Например, из событий DOM браузера, setTimeout, XHR или сторонних библиотек).

Попробуйте использовать $scope.$apply()сразу после того, как вы изменили местоположение и позвонили, replace()чтобы сообщить Angular, что все изменилось.

Ф Лекщас
источник
1
Работает как шарм. Я добавил код, который использовал в вашем посте, чтобы он работал :) Большое вам спасибо !!!
matsko
4
Чтобы получить лучшее представление о том, как применять $ работает с угловым и как работать вокруг него по вопросам, вот ссылка на то yearofmoo.com/2012/10/...
Мацко
2
@Skeater Вы можете просто ввести корневую область видимости и работать с ней следующим образом: factory ('xyz', ['$ rootScope', function ($ rootScope) {...}])
F Lekschas
4
может обернуть ваш обратный вызов с помощью $ timeout, и область действия будет применена правильно
JasonS
7
Как сказал JasonS, используйте $ timeout (function () {// примените изменения здесь}); У этого есть два преимущества: 1) Вам не нужен доступ к $ scope. 2) Вам не нужно беспокоиться о запуске $ apply alredy. По второй причине использование $ timeout часто является предпочтительным подходом.
ArneHugo
56

Вместо того, $location.path(...)чтобы изменять или обновлять страницу, я воспользовался сервисом $window. В Angular эта служба используется как интерфейс для windowобъекта, а windowобъект содержит свойство, locationкоторое позволяет вам обрабатывать операции, связанные с местоположением или URL-адресом.

Например, с помощью window.locationвы можете назначить новую страницу, например:

$window.location.assign('/');

Или обновите его, например:

$window.location.reload();

У меня это сработало. Это немного отличается от ожидаемого, но работает для поставленной цели.

Пауло Оливейра
источник
3
я тоже, $ location.path () не перенаправляет, когда url имеет параметры
Sudhakar
2
Это правильный ответ. Смотрите здесь
Ирвинг
28

У меня была такая же проблема, но мой вызов $ location УЖЕ был в дайджесте. Вызов $ apply () только что дал ошибку процесса $ дайджест.

Этот трюк сработал (и обязательно введите его $locationв свой контроллер):

$timeout(function(){ 
   $location...
},1);

Хотя не знаю, зачем это было нужно ...

Росс Р
источник
5
Нееет, это плохая идея. Просто проверьте фазу, если она находится в дайджесте, а затем вы можете пропустить применение. Angular догонит его и самостоятельно изменит URL: coderwall.com/p/ngisma
matsko
3
тайм-аут кажется мне грязным взломом. Если ваш href содержит "#", $ location.path () работает не так, как ожидалось. Просто удалите полностью href = "#" в теге a или просто установите href = "", и вам не нужно будет использовать $ timeout
Шанкар АРУЛ - jupyterdata.com
7
$$ phase - это частная переменная, к которой вы не должны пытаться получить доступ, потому что она может измениться в новой версии angularjs.
Blaise
7
Использование $ timeout может быть хитростью, но использование $$ phase - еще более серьезная хитрость. Как правило, не просматривайте и не трогайте ничего с префиксом $$.
nilskp
3
Примерно через 10 часов случайного взлома ... это решение сработало для меня!
Шакил
6

Мне пришлось встроить свое $location.path()утверждение вот так, потому что мой дайджест все еще работал:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }
Helzgate
источник
1
Спасибо за функцию, очень полезно!
Билл Эффин Мюррей,
для меня проблема заключалась в том, что мы использовали angular-block-ui, и это препятствовало обновлению местоположения адресной строки. мы украсили запрос $ http логическим значением, которое наш requestFilter подобрал, чтобы block-ui не запускался при этом конкретном вызове, и тогда все было в порядке.
matao
2

В моем случае проблема заключалась в отсутствии индикатора необязательного параметра ('?') В моей конфигурации шаблона.

Например:

.when('/abc/:id?', {
    templateUrl: 'views/abc.html',
    controller: 'abcControl'
})


$location.path('/abc');

Без символа запроса маршрут, очевидно, не изменился бы при подавлении параметра маршрута.

Виктор Гюго
источник
Это не конфигурация шаблона, а конфигурация маршрута.
Петр Доброгост
1

Если кто-то из вас использует Angular-ui / ui-router, используйте: $state.go('yourstate')вместо $location. Это помогло мне.

Elferone
источник
0

Это работает для меня (в CoffeeScript)

 $location.path '/url/path'
 $scope.$apply() if (!$scope.$$phase)
Fangxing
источник
0

На мой взгляд, многие ответы здесь кажутся немного взломанными (например, $ apply () или $ timeout), поскольку возня с $ apply () может привести к нежелательным ошибкам.

Обычно, когда $ location не работает, это означает, что что-то не было реализовано угловым способом.

В этом конкретном вопросе проблема, похоже, заключается в неугловой части AJAX. У меня была похожая проблема, когда перенаправление с использованием $ location должно происходить после выполнения обещания. Я хочу проиллюстрировать проблему на этом примере.

Старый код:

taskService.createTask(data).then(function(code){
            $location.path("task/" + code);
        }, function(error){});

Примечание: taskService.createTask возвращает обещание.

$ q - угловой способ использования обещаний:

let dataPromises = [taskService.createTask(data)];
        $q.all(dataPromises).then(function(response) {
                let code = response[0];
                $location.path("task/" + code);
            }, 
            function(error){});

Использование $ q для разрешения обещания решило проблему перенаправления.

Подробнее о сервисе $ q: https://docs.angularjs.org/api/ng/service/ $ q

iwan_gu
источник
-8
setTimeout(function() { $location.path("/abc"); },0);

это должно решить вашу проблему.

Акшай
источник
1
Запускать non-setTimeout - очень плохая идея. И, как сказал выше @matsko, $ timeout - не лучшая идея.
gonzofish