Combatendo o AngularJS executando o controlador duas vezes

Eu entendo que o AngularJS é executado através de algum código duas vezes, às vezes até mais, como $watch events, constantemente verificando os estados do modelo etc.

No entanto meu código:

 function MyController($scope, User, local) { var $scope.User = local.get(); // Get locally save user data User.get({ id: $scope.User._id.$oid }, function(user) { $scope.User = new User(user); local.save($scope.User); }); //... 

É executado duas vezes, inserindo 2 registros no meu database. Eu ainda estou claramente aprendendo como eu tenho batido minha cabeça contra isso por muito tempo!

O roteador de aplicativos especificou a navegação para MyController forma:

 $routeProvider.when('/', { templateUrl: 'pages/home.html', controller: MyController }); 

Mas eu também tinha isso em home.html :

 

Isso digeriu o controlador duas vezes. A remoção do atributo data-ng-controller do HTML resolveu o problema. Alternativamente, a propriedade controller: poderia ter sido removida da diretiva de roteamento.

Esse problema também aparece ao usar a navegação com guias. Por exemplo, app.js pode conter:

  .state('tab.reports', { url: '/reports', views: { 'tab-reports': { templateUrl: 'templates/tab-reports.html', controller: 'ReportsCtrl' } } }) 

A guia HTML de relatórios correspondentes pode se assemelhar a:

   

Isso também resultará na execução do controlador duas vezes.

AngularJS docs – ngController
Observe que você também pode append controladores ao DOM, declarando-o em uma definição de rota por meio do serviço $ route. Um erro comum é declarar o controlador novamente usando o ng-controller no próprio template. Isso fará com que o controlador seja conectado e executado duas vezes.

Quando você usa ngRoute com a diretiva ng-view , o controlador é anexado a esse elemento dom por padrão (ou ui-view se você usa o ui-roteador). Então você não precisará anexá-lo novamente no modelo.

Acabei de passar por isso, mas a questão era diferente da resposta aceita. Eu estou realmente deixando isso aqui para o meu futuro, para include os passos que eu passei para consertá-lo.

  1. Remover declarações de controlador redundantes
  2. Verifique as barras finais nas rotas
  3. Verifique se há ng-ifs
  4. Verifique se há alguma chamada desnecessária para o wrap ng-view (que eu acidentalmente deixei em uma ng-view que estava envolvendo minha ng-view real. Isso resultou em três chamadas para meus controladores).
  5. Se você está no Rails, você deve remover a gem do turbolinks do seu arquivo application.js . Eu perdi um dia inteiro para descobrir isso. Encontrei resposta aqui .
  6. Inicializando o aplicativo duas vezes com o ng-app e com o bootstrap. Combatendo o AngularJS executando o controlador duas vezes
  7. Ao usar $ compile em elemento inteiro em ‘link’-function da diretiva que também tem seu próprio controlador definido e usa callbacks deste controller em template via ng-click etc. Encontrou resposta aqui .

Só quero adicionar mais um caso quando o controlador pode iniciar duas vezes (isso é real para o angular.js 1.3.1):

 
Loading...

Neste caso, $ route.current já estará definido quando ng-view for init. Isso causa dupla boot.

Para corrigi-lo basta mudar ng-if para ng-show / ng-hide e tudo vai funcionar bem.

Gostaria de adicionar para referência:

A execução de código do controlador duplo também pode ser causada referenciando o controlador em uma diretiva que também é executada na página.

por exemplo

 return { restrict: 'A', controller: 'myController', link: function ($scope) { .... 

Quando você também tem ng-controller = “myController” no seu HTML

Ao usar o angular-ui-roteador com o Angular 1.3+, houve um problema sobre Renderizar visualizações duas vezes na transição da rota . Isso resultou na execução de controladores duas vezes também. Nenhuma das soluções propostas funcionou para mim.

No entanto, atualizando angular-ui-router de 0,2.11 para 0.2.13 resolveu problema para mim.

Eu rasguei meu aplicativo e todas as suas dependencies para bits sobre esta questão (detalhes aqui: AngularJS app iniciando duas vezes (tentei as soluções habituais ..) )

E no final, foi culpa do plugin Batarang Chrome.

Resolução nesta resposta :

Eu recomendo fortemente a primeira coisa na lista de alguém é desativá-lo por o post antes de alterar o código.

Eu tive o mesmo problema, em um aplicativo simples (sem roteamento e uma simples referência ng-controller) e o construtor do meu controlador rodou duas vezes. Finalmente, descobri que meu problema era a declaração a seguir para auto-bootstrap meu aplicativo AngularJS na minha visão Razor

  

Eu também tenho bootstrapped manualmente usando angular.bootstrap ou seja

 angular.bootstrap(document, [this.app.name]); 

então removendo um deles, funcionou para mim.

Se você souber que seu controlador está executando involuntariamente mais de uma vez, tente uma pesquisa em seus arquivos para obter o nome do controlador problemático, ex: search: MyController em todos os arquivos. É provável que tenha copiado e colado em algum outro arquivo html / js e você tenha esquecido de alterá-lo quando tiver desenvolvido ou usado esses partials / controllers. Fonte: Eu cometi este erro

Em alguns casos, sua diretiva é executada duas vezes quando você simplesmente não corrige a diretiva close like desta forma:

Some content

Isto irá executar sua diretiva duas vezes. Além disso, há outro caso frequente quando sua diretiva é executada duas vezes:

verifique se você não está incluindo sua diretiva em seu index.html DUAS VEZES !

Eu estava coçando minha cabeça sobre este problema com AngularJS 1.4 rc build, então percebi que nenhuma das respostas acima era aplicável desde que foi originada da nova biblioteca de roteadores para Angular 1.4 e Angular 2 no momento desta escrita. Portanto, estou lançando uma nota aqui para qualquer pessoa que esteja usando a nova biblioteca de rotas Angular.

Basicamente, se uma página html contiver uma diretiva ng-viewport para carregar partes do seu aplicativo, clicando em um hiperlink especificado com ng-link faria com que o controlador de destino do componente associado fosse carregado duas vezes. A diferença sutil é que, se o navegador já tiver carregado o controlador de destino, ao clicar novamente no mesmo hiperlink, o controlador será invocado apenas uma vez.

Ainda não encontrei uma solução viável, embora eu acredite que esse comportamento seja consistente com a observação levantada por shaunxu , e esperamos que este problema seja resolvido na futura construção da nova biblioteca de rotas e junto com as versões do AngularJS 1.4.

No meu caso, encontrei duas visões usando o mesmo controlador.

 $stateProvider.state('app', { url: '', views: { "viewOne@app": { controller: 'CtrlOne as CtrlOne', templateUrl: 'main/one.tpl.html' }, "viewTwo@app": { controller: 'CtrlOne as CtrlOne', templateUrl: 'main/two.tpl.html' } } }); 

O problema que estou encontrando pode ser tangencial, mas como o googling me trouxe a essa questão, isso pode ser apropriado. O problema mostra sua cabeça feia quando uso o roteador de interface do usuário, mas apenas quando tento atualizar a página com o botão de atualização do navegador. O aplicativo usa o roteador de interface do usuário com um estado abstrato pai e, em seguida, o estado filho do pai. Na function run() do aplicativo, há um $state.go('...child-state...') . O estado pai usa uma resolve e, a princípio, achei que talvez um controlador filho estivesse executando duas vezes.

Tudo está bem antes que o URL tenha o hash anexado.
www.someoldwebaddress.org

Então, uma vez que o URL tenha sido modificado pelo roteador de interface do usuário,
www.someoldwebaddress.org#/childstate

… e, em seguida, quando $stateChangeStart a página com o botão de atualização do navegador , o $stateChangeStart acionado duas vezes e cada vez aponta para o childstate .

A resolve no estado pai é o que está triggersndo duas vezes.

Talvez este seja um kludge; De qualquer forma, isso parece eliminar o problema para mim: na área de código em que $stateProvider é invocado pela primeira vez , primeiro verifique se o window.location.hash é uma string vazia. Se for, tudo é bom; se não for, defina o window.location.hash para uma string vazia. Então parece que o $state só tenta ir a algum lugar uma vez, em vez de duas vezes.

Além disso, se você não quiser depender da run padrão do aplicativo e state.go(...) , poderá tentar capturar o valor de hash e usar o valor de hash para determinar o estado filho em que estava antes da atualização da página, e adicione uma condição à área em seu código onde você define o state.go(...) .

No meu caso, foi por causa do padrão de URL que eu usei

minha url era como / ui / project /: parameter1 /: parameter2.

Eu não precisei de paramerter2 em todos os casos de mudança de estado. Nos casos em que não precisei do segundo parâmetro, minha url seria como / ui / project /: parameter1 /. E assim, sempre que eu tiver uma alteração de estado, meu controlador será atualizado duas vezes.

A solução foi definir o parâmetro2 como string vazia e fazer a mudança de estado.

Eu tive essa boot dupla acontecer por um motivo diferente. Para algumas transições de rota em meu aplicativo, eu quis forçar a rolagem para perto do topo da página (por exemplo, em resultados de pesquisa paginados … clique em próximo para ir ao topo da página 2).

Fiz isso adicionando um ouvinte ao $rootScope $on $viewContentLoaded que (com base em certas condições) executadas

 $location.hash('top'); 

Inadvertidamente isso estava fazendo com que minhas rotas fossem reavaliadas e os controladores fossem reinicializados

Meu problema era atualizar os parâmetros de pesquisa como $location.search('param', key);

Você pode ler mais sobre isso aqui

Controlador ficando chamado duas vezes devido a acrescentar params no url

No meu caso, renomear o controlador para um nome diferente resolveu o problema.

Houve um conflito de nomes de controladores com o módulo ” angular-ui-tree “: renomei meu controlador de “CatalogerTreeController” para ” TreeController ” e então este controlador começa a ser iniciado duas vezes na página onde a diretiva ” ui-tree ” é usada porque esta diretiva usa o controlador chamado ” TreeController “.

Eu tive o mesmo problema e depois de tentar todas as respostas eu finalmente encontrei que eu tinha uma diretiva na minha opinião que estava vinculada ao mesmo controlador.

 APP.directive('MyDirective', function() { return { restrict: 'AE', scope: {}, templateUrl: '../views/quiz.html', controller: 'ShowClassController' } }); 

Depois de remover a diretiva, o controlador parou de ser chamado duas vezes. Agora minha pergunta é, como pode usar esta diretiva vinculada ao escopo do controlador sem esse problema?

Acabei de resolver o meu, o que foi bastante decepcionante. É um aplicativo híbrido iônico, eu usei ui-roteador v0.2.13. No meu caso, há um epub reader (usando epub.js) que relatava continuamente “nenhum documento encontrado” quando eu navegava para a biblioteca de livros e selecionava qualquer outro livro. Quando eu recarreguei o livro do navegador estava sendo processado perfeitamente, mas quando eu selecionei outro livro tenho o mesmo problema novamente.

Minha resolução foi muito simples. Acabei de remover reload:true de $state.go("app.reader", { fileName: fn, reload: true }); na minha LibraryController

Eu tenho o mesmo problema em angular-route@1.6.7 , e isso porque a barra extra no final da rota regex:

 .when('/goods/publish/:classId/', option) 

para

 .when('/goods/publish/:classId', option) 

e funciona corretamente.

Para aqueles que usam a syntax ControllerAs, apenas declare o label do controlador no $ routeprovider da seguinte forma:

 $routeprovider .when('/link', { templateUrl: 'templateUrl', controller: 'UploadsController as ctrl' }) 

ou

 $routeprovider .when('/link', { templateUrl: 'templateUrl', controller: 'UploadsController' controllerAs: 'ctrl' }) 

Após declarar o $ routeprovider, não forneça o controlador como na visualização. Em vez disso, use o label na exibição.

Eu descobri que o meu é chamado duas vezes porque eu estava chamando o método duas vezes do meu html.

 `

A seção destacada estava causando o findX () a ser chamado duas vezes. Espero que ajude alguém.