La posizione di AngularJS $ non cambia il percorso


126

Sto riscontrando un problema con la modifica dell'URL della pagina dopo l'invio di un modulo.

Ecco il flusso della mia app:

  1. I percorsi sono impostati, l'URL è riconosciuto in qualche pagina del modulo.
  2. La pagina viene caricata, il controller imposta le variabili, le direttive vengono attivate.
  3. Viene emessa una direttiva sui moduli speciali che esegue l'invio di un modulo speciale utilizzando AJAX.
  4. Dopo l'esecuzione di AJAX (Angular non si occupa di AJAX), viene attivato un callback e la direttiva chiama la $scope.onAfterSubmitfunzione che imposta la posizione.

Il problema è che dopo aver impostato la posizione non succede nulla. Ho provato anche a impostare il parametro di posizione /... No. Ho anche provato a non inviare il modulo. Niente funziona.

Ho testato per vedere se il codice raggiunge la onAfterSubmitfunzione (cosa che fa).

Il mio unico pensiero è che in qualche modo l'ambito della funzione sia cambiato (dal momento che è stato chiamato da una direttiva), ma poi come può chiamare onAfterSubmitse l'ambito è cambiato?

Ecco il mio codice

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

Qualcuno può aiutarmi per favore?



Tieni presente che questo è stato creato un anno prima di quello.
Matsko,

Giusto e con il beneficio di un anno in più, l'altro ha una risposta accettata più precisamente corretta.
Jim G.

1
@JimG. questo non è un duplicato, questa domanda è di 4 anni fa, quella che colleghi, è di 2 anni fa.
Castro Roy,

Risposte:


298

Ho avuto un problema simile alcuni giorni fa. Nel mio caso il problema era che ho cambiato le cose con una libreria di terze parti (jQuery per essere precisi) e in questo caso anche se chiamare funzioni e impostare funzioni variabili Angular non riconosce sempre che ci sono cambiamenti, quindi non digerisce mai.

$ apply () viene utilizzato per eseguire un'espressione angolare dall'esterno della struttura angolare. (Ad esempio da eventi DOM del browser, setTimeout, XHR o librerie di terze parti).

Prova a usare $scope.$apply()subito dopo aver modificato la posizione e chiamato replace()per far sapere ad Angular che le cose sono cambiate.


1
Funziona come un fascino. Ho aggiunto il codice che ho usato nel tuo post per farlo funzionare :) Grazie mille !!!
Matsko,

4
Per avere un'idea migliore di come $ apply funziona con angular e come aggirare i suoi problemi, ecco un link per quell'annoofmoo.com/ 2012
10

2
@Skeater Puoi semplicemente iniettare l'ambito radice e operare su di esso in questo modo: factory ('xyz', ['$ rootScope', funzione ($ rootScope) {...}])
F Lekschas

4
può racchiudere il callback con $ timeout e l'ambito verrà applicato correttamente
JasonS

7
Come ha detto JasonS, usa $ timeout (function () {// applica le modifiche qui}); Ciò ha due vantaggi: 1) Non è necessario accedere a $ scope. 2) Non devi preoccuparti di $ apply alredy in esecuzione. Per il secondo motivo, l'utilizzo di $ timeout è spesso l'approccio preferito.
ArneHugo,

56

Invece di $location.path(...)cambiare o aggiornare la pagina, ho usato il servizio $window. In Angular questo servizio viene utilizzato come interfaccia per l' windowoggetto e l' windowoggetto contiene una proprietà locationche consente di gestire le operazioni relative alla posizione o agli elementi URL.

Ad esempio, con window.locationte puoi assegnare una nuova pagina, in questo modo:

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

O aggiornalo, in questo modo:

$window.location.reload();

Ha funzionato per me. È un po 'diverso da quello che ti aspetti, ma funziona per l'obiettivo dato.


3
anche io, $ location.path () non reindirizza quando url ha params
Sudhakar

2
Questa è la risposta corretta Vedi qui
Irving,

28

Ho avuto lo stesso problema, ma la mia chiamata a $ location era GIÀ all'interno di un digest. Chiamare $ apply () ha appena dato un $ digest già in errore di processo.

Questo trucco ha funzionato (e assicurati di iniettare $locationnel tuo controller):

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

Anche se non ho idea del perché questo fosse necessario ...


5
Nooo questa è una cattiva idea. Basta controllare la fase in caso sia all'interno di un digest e quindi è possibile saltare l'applicazione. Angular lo raggiungerà e cambierà l'URL da solo: coderwall.com/p/ngisma
matsko

3
il timeout mi sembra un brutto scherzo. Se il tuo href contiene "#", $ location.path () non funziona come previsto. Rimuovi completamente href = "#" sul tuo tag o imposta su href = "" e non dovrai utilizzare $ timeout
Shankar ARUL - jupyterdata.com

7
La fase $$ è una variabile privata a cui non dovresti tentare di accedere perché potrebbe cambiare in una nuova versione di angularjs.
Blaise,

7
L'uso di $ timeout potrebbe essere un hack, ma l'utilizzo di $$ phase è un hack ancora più grande. Generalmente, non visualizzare o toccare nulla con prefisso $$.
nilskp,

3
Dopo circa 10 ore di rottura di cose a caso ... questa soluzione ha funzionato per me!
Shakeel

6

Ho dovuto incorporare la mia $location.path()dichiarazione in questo modo perché il mio digest era ancora in esecuzione:

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

1
Grazie per la funzione, molto utile!
Bill Effin Murray,

per me il problema era che stavamo usando angular-block-ui e impediva l'aggiornamento della posizione della barra degli indirizzi. abbiamo decorato la richiesta $ http con un bool che il nostro requestFilter ha raccolto in modo che il blocco-ui non si innescasse su quella particolare chiamata, e quindi tutto andava bene.
matao,

2

Nel mio caso, il problema era l'indicatore di parametro opzionale ('?') Mancante nella mia configurazione del modello.

Per esempio:

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


$location.path('/abc');

Senza il carattere di interrogazione il percorso ovviamente non cambierebbe sopprimendo il parametro route.


Non è la configurazione del modello ma la configurazione del percorso.
Piotr Dobrogost,

1

Se qualcuno di voi utilizza Angular-ui / ui-router, utilizzare: $state.go('yourstate')anziché $location. Ha fatto il trucco per me.


0

Questo mi guasta (in CoffeeScript)

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

0

A mio avviso, molte delle risposte qui sembrano un po 'confuse (ad esempio $ apply () o $ timeout), dal momento che scherzare con $ apply () può portare a errori indesiderati.

Di solito, quando $ location non funziona significa che qualcosa non è stato implementato in modo angolare.

In questa particolare domanda, il problema sembra essere nella parte AJAX non angolare. Ho avuto un problema simile, in cui il reindirizzamento utilizzando $ location dovrebbe avvenire dopo che una promessa è stata risolta. Vorrei illustrare il problema in questo esempio.

Il vecchio codice:

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

Nota: taskService.createTask restituisce una promessa.

$ q - il modo angolare di usare le promesse:

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

L'uso di $ q per risolvere la promessa ha risolto il problema di reindirizzamento.

Ulteriori informazioni sul servizio $ q: https://docs.angularjs.org/api/ng/service/ $ q


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

dovrebbe risolvere il tuo problema.


1
Eseguire un non-setTimeout è una pessima idea. E, come ha detto @matsko sopra, $ timeout non è la migliore idea.
gonzofish,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.