La ubicación de AngularJS $ no cambia la ruta

126

Tengo un problema para cambiar la URL de la página después de enviar un formulario.

Aquí está el flujo de mi aplicación:

  1. Las rutas están configuradas, la URL se reconoce en alguna página de formulario.
  2. La página se carga, el controlador establece variables, las directivas se activan.
  3. Se activa una directiva de formulario especial que realiza un envío de formulario especial utilizando AJAX.
  4. Después de que se realiza el AJAX (Angular no se ocupa del AJAX), se activa una devolución de llamada y la directiva llama a la $scope.onAfterSubmitfunción que establece la ubicación.

El problema es que después de configurar la ubicación no pasa nada. También he intentado configurar el parámetro de ubicación /... No. También he intentado no enviar el formulario. Nada funciona.

He probado para ver si el código alcanza la onAfterSubmitfunción (lo que hace).

Mi único pensamiento es que de alguna manera se cambia el alcance de la función (ya que se llama desde una directiva), pero, de nuevo, ¿cómo se puede llamar onAfterSubmitsi el alcance cambió?

Aquí está mi código

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

alguien me puede ayudar por favor?

Matsko
fuente
1
posible duplicado de Angular $ location.path no funciona
Jim G.
Tenga en cuenta que esto fue creado un año antes de ese.
matsko
Correcto y con el beneficio de un año extra, el otro tiene una respuesta aceptada más precisa y correcta.
Jim G.
1
@JimG. esto no es un duplicado, esta pregunta es hace 4 años, la que enlazas es hace 2 años.
Castro Roy

Respuestas:

298

Tuve un problema similar hace unos días. En mi caso, el problema fue que cambié las cosas con una biblioteca de terceros (jQuery para ser precisos) y en este caso, aunque llamar a funciones y configurar variables funciona Angular no siempre reconoce que hay cambios, por lo que nunca digiere.

$ apply () se usa para ejecutar una expresión en angular desde fuera del marco angular. (Por ejemplo, desde eventos DOM del navegador, setTimeout, XHR o bibliotecas de terceros).

Intente usarlo $scope.$apply()inmediatamente después de haber cambiado la ubicación y haber llamado replace()para que Angular sepa que las cosas han cambiado.

F Lekschas
fuente
1
Funciona de maravilla. Agregué el código que usé en tu publicación para que funcione :) ¡Muchas gracias!
matsko
44
Para tener una mejor idea de cómo $ apply funciona con angular y cómo solucionar sus problemas, aquí hay un enlace para ese añoofmoo.com
2012
2
@Skeater Puede simplemente inyectar el alcance raíz y operarlo de la siguiente manera: factory ('xyz', ['$ rootScope', function ($ rootScope) {...}])
F Lekschas
44
puede ajustar su devolución de llamada con $ timeout y el alcance se aplicará correctamente
JasonS
77
Como dijo JasonS, use $ timeout (function () {// aplique los cambios aquí}); Esto tiene dos ventajas: 1) No necesita acceso a $ scope. 2) No tiene que preocuparse de que $ apply ya se ejecute. Por la segunda razón, usar $ timeout es a menudo el enfoque preferido.
ArneHugo
56

En lugar de $location.path(...)cambiar o actualizar la página, utilicé el servicio $window. En Angular, este servicio se utiliza como interfaz para el windowobjeto, y el windowobjeto contiene una propiedad locationque le permite manejar operaciones relacionadas con la ubicación o las cosas de URL.

Por ejemplo, con window.locationusted puede asignar una nueva página, como esta:

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

O actualizarlo, así:

$window.location.reload();

Funcionó para mi. Es un poco diferente de lo que espera pero funciona para el objetivo dado.

Paulo Oliveira
fuente
3
yo también, $ location.path () no redirige cuando url tiene parámetros
Sudhakar
2
Esta es la respuesta correcta. Ver aquí
Irving
28

Tuve el mismo problema, pero mi llamada a $ location YA estaba dentro de un resumen. Llamar a $ apply () acaba de dar un resumen de $ ya en error de proceso.

Este truco funcionó (y asegúrese de inyectar $locationen su controlador):

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

Aunque no tengo idea de por qué esto era necesario ...

Ross R
fuente
55
Nooo, esta es una mala idea. Simplemente verifique la fase en caso de que esté dentro de un resumen y luego puede omitir la solicitud. Angular lo alcanzará y cambiará la URL por sí solo: coderwall.com/p/ngisma
matsko
3
el tiempo de espera me parece un truco sucio. Si su href contiene "#", $ location.path () no funciona como se esperaba. Simplemente elimine completamente href = "#" en su etiqueta o simplemente configúrelo en href = "" y no necesitará usar $ timeout
Shankar ARUL - jupyterdata.com
77
$$ phase es una variable privada a la que no debe intentar acceder porque podría cambiar en una nueva versión de angularjs.
Blaise
77
Usar $ timeout podría ser un hack, pero usar $$ phase es un hack aún más grande. En general, no vea ni toque nada con el prefijo $$.
nilskp
3
Después de aproximadamente 10 horas de cosas al azar rompiendo ... ¡esta solución funcionó para mí!
Shakeel
6

Tuve que incrustar mi $location.path()declaración de esta manera porque mi resumen todavía se estaba ejecutando:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }
Helzgate
fuente
1
Gracias por la función, muy útil!
Bill Effin Murray
para mí el problema era que estábamos usando angular-block-ui y estaba evitando la actualización de la ubicación de la barra de direcciones. Decoramos la solicitud $ http con un bool que nuestro requestFilter recogió para que block-ui no se activara en esa llamada en particular, y luego todo estuvo bien.
matao
2

En mi caso, el problema era que faltaba el indicador de parámetro opcional ('?') En la configuración de mi plantilla.

Por ejemplo:

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


$location.path('/abc');

Sin el carácter de interrogación, la ruta obviamente no cambiaría suprimiendo el parámetro de ruta.

Victor Hugo
fuente
No es configuración de plantilla sino configuración de ruta.
Piotr Dobrogost
1

Si alguno de ustedes está usando Angular-ui / ui-router, use: en $state.go('yourstate')lugar de $location. Fue el truco para mí.

Elferona
fuente
0

Esto funciona para mí (en CoffeeScript)

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

En mi opinión, muchas de las respuestas aquí parecen un poco extravagantes (por ejemplo, $ apply () o $ timeout), ya que jugar con $ apply () puede provocar errores no deseados.

Por lo general, cuando la ubicación $ no funciona, significa que algo no se implementó de forma angular.

En esta pregunta en particular, el problema parece estar en la parte no angular de AJAX. Tuve un problema similar, donde la redirección usando $ location debería tener lugar después de que se resuelva una promesa. Me gustaría ilustrar el problema en este ejemplo.

El viejo código:

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

Nota: taskService.createTask devuelve una promesa.

$ q: la forma angular de usar promesas:

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

El uso de $ q para resolver la promesa resolvió el problema de redirección.

Más sobre el servicio $ q: https://docs.angularjs.org/api/ng/service/ $ q

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

debería resolver tu problema.

Akshay
fuente
1
Ejecutar un tiempo de espera no establecido es una muy mala idea. Y, como dijo @matsko anteriormente, $ timeout no es la mejor idea.
gonzofish