Lokalizacja AngularJS $ nie zmienia ścieżki


126

Mam problem ze zmianą adresu URL strony po przesłaniu formularza.

Oto przepływ mojej aplikacji:

  1. Trasy są ustawione, URL jest rozpoznawany do jakiejś strony formularza.
  2. Ładowanie strony, kontroler ustawia zmienne, uruchamiane są dyrektywy.
  3. Uruchamiana jest specjalna dyrektywa formularza, która wykonuje przesyłanie specjalnego formularza za pomocą AJAX.
  4. Po wykonaniu AJAX (Angular nie dba o AJAX), wywoływane jest wywołanie zwrotne, a dyrektywa wywołuje $scope.onAfterSubmitfunkcję, która ustawia lokalizację.

Problem w tym, że po ustawieniu lokalizacji nic się nie dzieje. Próbowałem również ustawić parametr lokalizacji na /... Nie. Próbowałem też nie przesłać formularza. Nic nie działa.

Przetestowałem, aby sprawdzić, czy kod dociera do onAfterSubmitfunkcji (co robi).

Moją jedyną myślą jest to, że w jakiś sposób zakres funkcji został zmieniony (ponieważ została wywołana z dyrektywy), ale z drugiej strony, jak może wywołać, onAfterSubmitjeśli zakres się zmienił?

Oto mój kod

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'];

Czy ktoś może mi pomóc?



Pamiętaj, że ten został utworzony rok wcześniej.
matsko

Słusznie i po dodatkowym roku, drugi ma dokładniejszą, zaakceptowaną odpowiedź.
Jim G.

1
@JimG. to nie jest duplikat, to pytanie jest 4 lata temu, to, które łączysz, jest 2 lata temu.
Castro Roy

Odpowiedzi:


298

Kilka dni temu miałem podobny problem. W moim przypadku problem polegał na tym, że zmieniłem rzeczy za pomocą biblioteki innej firmy (a dokładniej jQuery) iw tym przypadku chociaż wywoływanie funkcji i ustawianie zmiennych działa, Angular nie zawsze rozpoznaje, że są zmiany, więc nigdy nie trawi.

$ Apply () służy do wykonywania wyrażenia kątowego spoza struktury kątowej. (Na przykład ze zdarzeń DOM przeglądarki, setTimeout, XHR lub bibliotek innych firm).

Spróbuj użyć $scope.$apply()zaraz po zmianie lokalizacji i wywołaniu, replace()aby Angular wiedział, że coś się zmieniło.


1
Działa jak marzenie. Dodałem kod, którego użyłem do Twojego postu, aby działał :) Dziękuję bardzo !!!
matsko

4
Aby lepiej zrozumieć, jak $ Apply
działa z angularem

2
@Skeater Możesz po prostu wstrzyknąć zakres główny i działać na nim w następujący sposób: factory ('xyz', ['$ rootScope', function ($ rootScope) {...}])
F Lekschas

4
może zawrzeć twoje wywołanie zwrotne $ timeout, a zakres zostanie poprawnie zastosowany
JasonS

7
Jak powiedział JasonS, użyj $ timeout (function () {// zastosuj zmiany tutaj}); Ma to dwie zalety: 1) Nie potrzebujesz dostępu do $ scope. 2) Nie musisz się martwić, że bierzesz udział w aplikacji. Z drugiego powodu preferowanym podejściem jest często użycie $ timeout.
ArneHugo

56

Zamiast $location.path(...)zmieniać lub odświeżać stronę, skorzystałem z usługi $window. W Angular ta usługa jest używana jako interfejs do windowobiektu, a windowobiekt zawiera właściwość, locationktóra umożliwia obsługę operacji związanych z lokalizacją lub adresem URL.

Na przykład za pomocą window.locationmożesz przypisać nową stronę, na przykład:

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

Lub odśwież ją, na przykład:

$window.location.reload();

U mnie zadziałało To trochę różni się od tego, czego się spodziewasz, ale działa dla danego celu.


3
ja też, $ location.path () nie przekierowuje, gdy adres URL ma parametry
Sudhakar

2
To jest poprawna odpowiedź. Zobacz tutaj
Irving

28

Miałem ten sam problem, ale moje połączenie z $ location było JUŻ w skrócie. Wywołanie $ apply () spowodowało, że podsumowanie $ już trwa.

Ta sztuczka zadziałała (i pamiętaj, aby wstrzyknąć $locationdo kontrolera):

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

Chociaż nie mam pojęcia, dlaczego było to konieczne ...


5
Nieee, to zły pomysł. Po prostu sprawdź, czy faza jest w skrócie, a następnie możesz pominąć stosowanie. Angular dogoni to i samodzielnie zmieni adres URL: coderwall.com/p/ngisma
matsko

3
Timeout wydaje mi się brudnym hackem. Jeśli twój href zawiera "#", $ location.path () nie działa zgodnie z oczekiwaniami. Po prostu usuń całkowicie href = "#" ze swojego tagu lub po prostu ustaw na href = "", a nie będziesz musiał używać $ timeout
Shankar ARUL - jupyterdata.com

7
Faza $$ to zmienna prywatna, do której nie powinieneś uzyskiwać dostępu, ponieważ może się ona zmienić w nowej wersji angularjs.
Blaise,

7
Używanie $ timeout może być hackiem, ale użycie fazy $$ to jeszcze poważniejszy hack. Ogólnie nie przeglądaj ani nie dotykaj niczego z prefiksem $$.
nilskp

3
Po około 10 godzinach przypadkowego zepsucia się rzeczy ... to rozwiązanie zadziałało!
Shakeel

6

Musiałem umieścić moje $location.path()oświadczenie w ten sposób, ponieważ moje podsumowanie wciąż działało:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }

1
Dzięki za funkcję, bardzo przydatna!
Bill Effin Murray

dla mnie problem polegał na tym, że używaliśmy angular-block-ui i uniemożliwiało to aktualizację lokalizacji paska adresu. udekorowaliśmy żądanie $ http wartością bool odebraną przez nasz requestFilter, aby blok-ui nie wyzwalał tego konkretnego wywołania, a potem wszystko było w porządku.
matao

2

W moim przypadku problemem był brak opcjonalnego wskaźnika parametru („?”) W mojej konfiguracji szablonu.

Na przykład:

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


$location.path('/abc');

Bez znaku zapytania trasa oczywiście nie zmieniłaby się, pomijając parametr trasy.


To nie jest konfiguracja szablonu, ale konfiguracja trasy.
Piotr Dobrogost

1

Jeśli ktoś z was korzysta z routera Angular-ui / ui-router, użyj: $state.go('yourstate')zamiast $location. Dla mnie to załatwiło.


0

To działa dla mnie (w CoffeeScript)

 $location.path '/url/path'
 $scope.$apply() if (!$scope.$$phase)

0

Moim zdaniem wiele z odpowiedzi wydaje się trochę nietypowych (np. $ Apply () lub $ timeout), ponieważ mieszanie się z $ apply () może prowadzić do niechcianych błędów.

Zwykle, gdy lokalizacja $ nie działa, oznacza to, że coś nie zostało zaimplementowane w sposób kątowy.

W tym konkretnym pytaniu problem wydaje się tkwić w nie-kątowej części AJAX. Miałem podobny problem, w którym przekierowanie za pomocą $ location powinno nastąpić po rozwiązaniu obietnicy. Chciałbym zilustrować problem na tym przykładzie.

Stary kod:

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

Uwaga: taskService.createTask zwraca obietnicę.

$ q - kątowy sposób używania obietnic:

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

Użycie $ q do rozwiązania obietnicy rozwiązało problem z przekierowaniem.

Więcej o usłudze $ q: https://docs.angularjs.org/api/ng/service/ $ q


-8
setTimeout(function() { $location.path("/abc"); },0);

to powinno rozwiązać twój problem.


1
Uruchamianie non-setTimeout to bardzo zły pomysł. Jak powiedział @matsko powyżej, $ timeout nie jest najlepszym pomysłem.
gonzofish,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.