AngularJS $ location não alterando o caminho

126

Estou com um problema ao alterar o URL da página após o envio de um formulário.

Aqui está o fluxo do meu aplicativo:

  1. As rotas são definidas, o URL é reconhecido em alguma página do formulário.
  2. Página carrega, controlador define variáveis, diretivas são acionadas.
  3. Uma diretiva de formulário especial é acionada que executa um envio de formulário especial usando AJAX.
  4. Depois que o AJAX é executado (o Angular não cuida do AJAX), um retorno de chamada é acionado e a diretiva chama a $scope.onAfterSubmitfunção que define o local.

O problema é que, depois de definir o local, nada acontece. Eu tentei definir o parâmetro de localização /também ... Não. Também tentei não enviar o formulário. Nada funciona.

Eu testei para ver se o código atinge a onAfterSubmitfunção (o que faz).

Meu único pensamento é que, de alguma forma, o escopo da função é alterado (desde que é chamado de uma diretiva), mas, novamente, como ele pode chamar onAfterSubmitse o escopo foi alterado?

Aqui está o meu 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'];

Alguém me pode ajudar, se faz favor?

Matsko
fonte
1
possível duplicata Angular $ location.path não funciona
Jim G.
Lembre-se de que isso foi criado um ano antes daquele.
matsko
Certo e com o benefício de um ano extra, o outro tem uma resposta aceita com mais precisão.
Jim G.
1
@JimG. isto não é uma cópia, esta pergunta é de 4 anos atrás, a que você vincula, é de 2 anos atrás.
Castro Roy

Respostas:

298

Eu tive um problema semelhante há alguns dias. No meu caso, o problema era que eu mudei as coisas com uma biblioteca de terceiros (jQuery para ser mais preciso) e, nesse caso, embora chamar funções e definir variáveis ​​funcionem, o Angular nem sempre reconhece que há alterações, portanto, nunca é digerido.

$ apply () é usado para executar uma expressão em angular de fora da estrutura angular. (Por exemplo, nos eventos DOM do navegador, setTimeout, XHR ou bibliotecas de terceiros).

Tente usar $scope.$apply()logo após alterar o local e ligar replace()para avisar a Angular que as coisas mudaram.

F Lekschas
fonte
1
Funciona como um encanto. Eu adicionei o código que usei em sua postagem para fazê-la funcionar :) Muito obrigado !!!
matsko
4
Para ter uma idéia melhor de como $ aplicar obras com angular e como trabalhar em torno dele de questões, aqui está um link para que yearofmoo.com/2012/10/...
matsko
2
@ Skeater Você pode simplesmente injetar o escopo raiz e operá-lo da seguinte maneira: factory ('xyz', ['$ rootScope', function ($ rootScope) {...}])
F Lekschas
4
pode envolver o retorno de chamada com $ de tempo limite e o escopo será devidamente aplicada
jasons
7
Como o JasonS disse, use $ timeout (function () {// aplique alterações aqui}); Isso tem duas vantagens: 1) Você não precisa acessar o $ scope. 2) Você não precisa se preocupar com $ apply já em execução. Pela segunda razão, usar $ timeout geralmente é a abordagem preferida.
ArneHugo
56

Em vez de $location.path(...)alterar ou atualizar a página, usei o serviço $window. No Angular, esse serviço é usado como interface para o windowobjeto e o windowobjeto contém uma propriedade locationque permite lidar com operações relacionadas ao local ou ao material da URL.

Por exemplo, window.locationvocê pode atribuir uma nova página, assim:

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

Ou atualize-o assim:

$window.location.reload();

Funcionou para mim. É um pouco diferente do esperado, mas funciona para o objetivo especificado.

Paulo Oliveira
fonte
3
eu também, $ location.path () não redireciona quando o url tem parâmetros
4172 Sudhakar
2
Essa é a resposta correta. Veja aqui
Irving
28

Eu tive esse mesmo problema, mas minha ligação para $ location JÁ estava dentro de um resumo. Chamar $ apply () acabou de fornecer um $ digest já em erro no processo.

Este truque funcionou (e certifique-se de injetar $locationno seu controlador):

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

Embora nenhuma idéia do por que isso era necessário ...

Ross R
fonte
5
Não, isso é uma má ideia. Basta verificar se a fase está dentro de um resumo e, em seguida, você pode pular a aplicação. Angular irá alcançá-lo e mudar a URL no seu próprio: coderwall.com/p/ngisma
matsko
3
timeout parece um truque sujo para mim. Se o seu href contiver "#", o $ location.path () não funcionará conforme o esperado. Basta remover inteiramente href = "#" no seu uma etiqueta ou apenas definir a href = "" e você não iria precisar usar $ Timeout
Shankar Arul - jupyterdata.com
7
$$ phase é uma variável privada que você não deve tentar acessar porque pode mudar em uma nova versão do angularjs.
Blaise
7
Usar $ timeout pode ser um hack, mas usar a fase $$ é um hack ainda maior. Geralmente, não exiba nem toque em nada prefixado com $$.
Nskp 15/09/2014
3
Após cerca de 10 horas de coisas aleatórias quebrando ... essa solução funcionou para mim!
Shakeel
6

Eu tive que incorporar minha $location.path()declaração assim porque meu resumo ainda estava sendo executado:

       function routeMe(data) {                
            var waitForRender = function () {
                if ($http.pendingRequests.length > 0) {
                    $timeout(waitForRender);
                } else {
                    $location.path(data);
                }
            };
            $timeout(waitForRender);
        }
Helzgate
fonte
1
Obrigado pela função, muito útil!
Bill Murray Effin
para mim, o problema era que estávamos usando o angular-block-ui e estava impedindo a atualização do local da barra de endereço. decoramos a solicitação $ http com um bool que nosso requestFilter captou para que a ui do bloco não fosse acionada nessa chamada específica e, então, tudo estava bem.
matao 23/11
2

No meu caso, o problema era o indicador de parâmetro opcional ('?') Ausente na minha configuração de modelo.

Por exemplo:

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


$location.path('/abc');

Sem o caractere de interrogação, a rota obviamente não mudaria suprimindo o parâmetro de rota.

Victor Hugo
fonte
Não é uma configuração de modelo, mas uma configuração de rota.
Piotr Dobrogost
1

Se algum de vocês estiver usando o Angular-ui / ui-router, use: em $state.go('yourstate')vez de $location. Isso fez o truque para mim.

Elferone
fonte
0

Isso funciona para mim (no CoffeeScript)

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

Na minha opinião, muitas das respostas aqui parecem um pouco hacky (por exemplo, $ apply () ou $ timeout), uma vez que mexer com $ apply () pode levar a erros indesejados.

Normalmente, quando o local $ não funciona, significa que algo não foi implementado da maneira angular.

Nesta questão em particular, o problema parece estar na parte AJAX não angular. Eu tive um problema semelhante, em que o redirecionamento usando $ location deveria ocorrer após a promessa ser resolvida. Eu gostaria de ilustrar o problema neste exemplo.

O código antigo:

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

Nota: taskService.createTask retorna uma promessa.

$ q - a maneira angular de usar promessas:

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

O uso de $ q para resolver a promessa resolveu o problema de redirecionamento.

Mais informações sobre o serviço $ q: https://docs.angularjs.org/api/ng/service/ $ q

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

isso deve resolver seu problema.

Akshay
fonte
1
Executar um non-setTimeout é uma péssima idéia. E, como @matsko disse acima, $ timeout não é a melhor ideia.
gonzofish