AngularJS $ Ort ändert den Pfad nicht

126

Ich habe ein Problem beim Ändern der URL der Seite, nachdem ein Formular gesendet wurde.

Hier ist der Ablauf meiner App:

  1. Routen werden festgelegt, URL wird zu einer Formularseite erkannt.
  2. Seiten wird geladen, Controller setzt Variablen, Direktiven werden ausgelöst.
  3. Es wird eine spezielle Formularanweisung ausgelöst, die eine spezielle Formularübermittlung mit AJAX durchführt.
  4. Nachdem der AJAX ausgeführt wurde (Angular kümmert sich nicht um den AJAX), wird ein Rückruf ausgelöst und die Direktive ruft die $scope.onAfterSubmitFunktion auf, die den Speicherort festlegt.

Das Problem ist, dass nach dem Festlegen des Standorts nichts passiert. Ich habe auch versucht, den Standortparameter auf /... Nein. Ich habe auch versucht, das Formular nicht einzureichen. Nichts funktioniert.

Ich habe getestet, ob der Code die onAfterSubmitFunktion erreicht (was er tut).

Mein einziger Gedanke ist, dass sich der Umfang der Funktion irgendwie ändert (da sie von einer Direktive aufgerufen wird), aber wie kann sie dann wieder aufgerufen werden? onAfterSubmit wenn sich der Umfang ändert?

Hier ist mein Code

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

Kann mir bitte jemand helfen?

Matsko
quelle
1
Mögliches Duplikat von Angular $ location.path funktioniert nicht
Jim G.
Denken Sie daran, dass dies ein Jahr zuvor erstellt wurde.
Matsko
Richtig und mit dem Vorteil eines zusätzlichen Jahres hat der andere eine genauere, richtig akzeptierte Antwort.
Jim G.
1
@ JimG. Dies ist kein Duplikat. Diese Frage ist vor 4 Jahren, die, die Sie verlinken, ist vor 2 Jahren.
Castro Roy

Antworten:

298

Ich hatte vor einigen Tagen ein ähnliches Problem. In meinem Fall bestand das Problem darin, dass ich Dinge mit einer Bibliothek eines Drittanbieters geändert habe (um genau zu sein jQuery), und in diesem Fall erkennt Angular nicht immer, dass es Änderungen gibt, obwohl es das Aufrufen von Funktionen und das Setzen von Variablen funktioniert, sodass es niemals verdaut.

$ apply () wird verwendet, um einen Ausdruck in Winkel von außerhalb des Winkelrahmens auszuführen. (Zum Beispiel aus Browser-DOM-Ereignissen, setTimeout-, XHR- oder Bibliotheken von Drittanbietern).

Versuchen Sie, $scope.$apply()direkt zu verwenden, nachdem Sie den Standort geändert und replace()Angular darüber informiert haben, dass sich die Dinge geändert haben.

F Lekschas
quelle
1
Klappt wunderbar. Ich habe den Code, den ich verwendet habe, in Ihren Beitrag eingefügt, damit er funktioniert :) Vielen Dank !!!
Matsko
4
Um eine bessere Vorstellung davon zu bekommen, wie $ apply mit Angular
matsko
2
@Skeater Sie können einfach den Root-Bereich einfügen und wie folgt bearbeiten: factory ('xyz', ['$ rootScope', Funktion ($ rootScope) {...}])
F Lekschas
4
kann Ihren Rückruf mit $
timeout abschließen
7
Verwenden Sie, wie JasonS sagte, $ timeout (function () {// Änderungen hier anwenden}); Dies hat zwei Vorteile: 1) Sie benötigen keinen Zugriff auf $ scope. 2) Sie müssen sich keine Sorgen machen, dass $ apply bereits ausgeführt wird. Aus dem zweiten Grund ist die Verwendung von $ timeout häufig der bevorzugte Ansatz.
ArneHugo
56

Anstatt $location.path(...)die Seite zu ändern oder zu aktualisieren, habe ich den Dienst verwendet $window. In Angular wird dieser Dienst als Schnittstelle zum windowObjekt verwendet, und das windowObjekt enthält eine Eigenschaft location, mit der Sie Vorgänge ausführen können, die sich auf den Speicherort oder das URL-Material beziehen.

Mit können Sie beispielsweise window.locationeine neue Seite wie folgt zuweisen:

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

Oder aktualisieren Sie es wie folgt:

$window.location.reload();

Es hat bei mir funktioniert. Es ist ein bisschen anders als erwartet, funktioniert aber für das vorgegebene Ziel.

Paulo Oliveira
quelle
3
Ich auch, $ location.path () leitet nicht um, wenn URL params hat
Sudhakar
2
Dies ist die richtige Antwort. Siehe hier
Irving
28

Ich hatte das gleiche Problem, aber mein Anruf bei $ location war BEREITS innerhalb eines Digests. Das Aufrufen von $ apply () ergab nur einen $ Digest, der bereits einen Prozessfehler aufwies.

Dieser Trick hat funktioniert (und muss unbedingt $locationin Ihren Controller injiziert werden):

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

Obwohl keine Ahnung, warum dies notwendig war ...

Ross R.
quelle
5
Nein, das ist eine schlechte Idee. Überprüfen Sie einfach, ob sich die Phase in einem Digest befindet, und überspringen Sie dann die Anwendung. Angular wird es einholen und die URL selbst ändern
matsko
3
Timeout scheint mir ein schmutziger Hack zu sein. Wenn Ihre href "#" enthält, funktioniert $ location.path () nicht wie erwartet. Entfernen Sie einfach ganz href = „#“ auf einen Tag oder nur auf href = „“ und Sie würde nicht $ timeout verwenden müssen
Shankar Arul - jupyterdata.com
7
$$ phase ist eine private Variable, auf die Sie nicht zugreifen sollten, da sie sich in einer neuen anglejs-Version möglicherweise ändert.
Blaise
7
Die Verwendung von $ timeout mag ein Hack sein, aber die Verwendung von $$ phase ist ein noch größerer Hack. Zeigen oder berühren Sie im Allgemeinen nichts, dem $$ vorangestellt ist.
Nilskp
3
Nach ungefähr 10 Stunden zufälliger Dinge hat diese Lösung für mich funktioniert!
Shakeel
6

Ich musste meine $location.path()Aussage so einbetten, weil mein Digest noch lief:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }
Helzgate
quelle
1
Danke für die Funktion, sehr nützlich!
Bill Effin Murray
Für mich war das Problem, dass wir Angular-Block-UI verwendeten und die Aktualisierung der Adressleistenposition verhinderte. Wir haben die $ http-Anfrage mit einem Bool dekoriert, den unser requestFilter aufgenommen hat, damit die Block-UI bei diesem bestimmten Aufruf nicht ausgelöst wurde, und dann war alles in Ordnung.
Matao
2

In meinem Fall war das Problem, dass der optionale Parameterindikator ('?') In meiner Vorlagenkonfiguration fehlte.

Beispielsweise:

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


$location.path('/abc');

Ohne das Abfragezeichen würde sich die Route offensichtlich nicht ändern, indem der Routenparameter unterdrückt wird.

Victor Hugo
quelle
Es ist keine Vorlagenkonfiguration, sondern eine Routenkonfiguration.
Piotr Dobrogost
1

Wenn einer von Ihnen den Angular-ui / ui-Router verwendet, verwenden Sie: $state.go('yourstate')anstelle von $location. Es hat den Trick für mich getan.

Elferone
quelle
0

Das funktioniert für mich (in CoffeeScript)

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

Meiner Meinung nach scheinen viele der Antworten hier etwas hackig zu sein (z. B. $ apply () oder $ timeout), da das Herumspielen mit $ apply () zu unerwünschten Fehlern führen kann.

Wenn der $ -Standort nicht funktioniert, bedeutet dies normalerweise, dass etwas nicht im Winkel implementiert wurde.

In dieser speziellen Frage scheint das Problem im nicht eckigen AJAX-Teil zu liegen. Ich hatte ein ähnliches Problem, bei dem die Umleitung unter Verwendung von $ location erfolgen sollte, nachdem ein Versprechen gelöst wurde. Ich möchte das Problem an diesem Beispiel veranschaulichen.

Der alte Code:

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

Hinweis: taskService.createTask gibt ein Versprechen zurück.

$ q - die eckige Art, Versprechen zu verwenden:

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

Die Verwendung von $ q zur Lösung des Versprechens löste das Umleitungsproblem.

Weitere Informationen zum $ q-Service: https://docs.angularjs.org/api/ng/service/ $ q

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

es sollte dein Problem lösen.

Akshay
quelle
1
Das Ausführen eines Nicht-SetTimeout ist eine sehr schlechte Idee. Und wie @matsko oben sagte, ist $ timeout nicht die beste Idee.
Gonzofish