Combattere il controller di esecuzione AngularJS due volte

Comprendo che AngularJS esegue il codice due volte, a volte anche di più, come gli eventi di $watch , il controllo costante degli stati del modello ecc.

Comunque il mio codice:

 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); }); //... 

Viene eseguito due volte, inserendo 2 record nel mio DB. Sto ancora imparando come ho battuto la testa contro questo per secoli!

Il router dell’app ha specificato la navigazione su MyController modo:

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

Ma ho avuto anche questo in home.html :

 

Questo ha digerito il controller due volte. La rimozione dell’attributo data-ng-controller dall’HTML ha risolto il problema. In alternativa, il controller: proprietà potrebbe essere stata rimossa dalla direttiva di routing.

Questo problema appare anche quando si utilizza la navigazione a tabs. Ad esempio, app.js potrebbe contenere:

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

La scheda HTML corrispondente potrebbe essere simile a:

   

Ciò comporterà anche l’esecuzione del controller due volte.

AngularJS docs – ngController
Si noti che è anche ansible colbind i controller al DOM dichiarandolo in una definizione di rotta tramite il servizio $ route. Un errore comune è quello di dichiarare nuovamente il controller utilizzando ng-controller nel modello stesso. Ciò farà sì che il controller venga collegato ed eseguito due volte.

Quando si utilizza ngRoute con la direttiva ng-view , il controller viene collegato a quell’elemento dom per impostazione predefinita (o ui-view se si utilizza ui-router). Quindi non sarà necessario allegarlo di nuovo nel modello.

L’ho appena esaminato, ma il problema era diverso dalla risposta accettata. Sto davvero lasciando questo qui per il mio futuro io, per includere i passaggi che ho passato per risolverlo.

  1. Rimuovere le dichiarazioni ridondanti del controllore
  2. Controlla le barre finali nelle rotte
  3. Controlla per ng-ifs
  4. Controlla se sono state necessarie chiamate di ng-view (mi sono accidentalmente lasciato in una ng-view che stava avvolgendo la mia attuale ng-view . Ciò ha comportato tre chiamate ai miei controller.)
  5. Se sei su Rails, dovresti rimuovere la gem turbolinks dal tuo file application.js . Ho perso un giorno intero per scoprirlo. Trovato risposta qui .
  6. Inizializzando l’app due volte con ng-app e con bootstrap. Combattere il controller di esecuzione AngularJS due volte
  7. Quando si utilizza $ compile su tutto l’elemento nella funzione ‘link’ della direttiva che ha anche il proprio controller definito e utilizza i callback di questo controller nel modello tramite ng-clic ecc. Trovato risposta qui .

Voglio solo aggiungere un altro caso quando il controller può avviare due volte (questo è vero per angular.js 1.3.1):

 
Loading...

In questo caso $ route.current sarà già impostato quando ng-view verrà avviato. Ciò causa una doppia inizializzazione.

Per risolvere il problema basta cambiare ng-if in ng-show / ng-hide e tutto funzionerà bene.

Vorrei aggiungere per riferimento:

L’esecuzione del codice del controller doppio può anche essere causata facendo riferimento al controller in una direttiva che viene eseguita anche sulla pagina.

per esempio

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

Quando hai anche ng-controller = “myController” nel tuo HTML

Quando si utilizza angular -ui-router con Angular 1.3+, si è verificato un problema sulle viste di rendering due volte sulla transizione del percorso . Ciò ha comportato anche l’esecuzione di controller due volte. Nessuna delle soluzioni proposte ha funzionato per me.

Tuttavia, l’aggiornamento di angular angular-ui-router da 0.2.11 a 0.2.13 ha risolto il problema per me.

Ho strappato la mia app e tutte le sue dipendenze a bit su questo problema (dettagli qui: l’ app AngularJS ha avviato due volte (provato le solite soluzioni ..) )

E alla fine, è stata colpa di tutto il plugin di Batarang Chrome.

Risoluzione in questa risposta :

Consiglio vivamente che la prima cosa sulla lista di tutti è disabilitarla per posta prima di modificare il codice.

Ho avuto lo stesso problema, in una semplice app (senza routing e un semplice riferimento al controller ng) e il costruttore del mio controller è stato eseguito due volte. Alla fine, ho scoperto che il mio problema era la seguente dichiarazione di auto-bootstrap della mia applicazione AngularJS nella mia vista Razor

  

L’ho anche riavviato manualmente usando angular.bootstrap ie

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

così togliendone uno, ha funzionato per me.

Se si sa che il controller viene eseguito non intenzionalmente più di una volta, provare una ricerca attraverso i propri file per il nome del controller che causa l’errore, ad es .: search: MyController attraverso tutti i file. Probabilmente è stato copiato in un altro file html / js e ti sei dimenticato di cambiarlo quando hai iniziato a sviluppare o usare quei partial / controller. Fonte: ho fatto questo errore

In alcuni casi la direttiva viene eseguita due volte quando semplicemente non si corregge la direttiva come in questo modo:

Some content

Questo eseguirà la tua direttiva due volte. C’è anche un altro caso spesso quando la tua direttiva viene eseguita due volte:

assicurati di non includere la direttiva nel tuo index.html DUE VOLTE !

Mi sono grattato la testa su questo problema con AngularJS 1.4 rc build, quindi mi sono reso conto che nessuna delle risposte precedenti era applicabile poiché era stata originata dalla nuova libreria del router per Angular 1.4 e Angular 2 al momento della stesura di questo documento. Pertanto, sto rilasciando una nota qui per chiunque potrebbe utilizzare la nuova libreria di rotte Angular.

Fondamentalmente se una pagina HTML contiene una direttiva ng-viewport per il caricamento di parti della tua app, facendo clic su un collegamento ipertestuale specificato con ng-link causerebbe il caricamento del controller di destinazione del componente associato due volte. La sottile differenza è che, se il browser ha già caricato il controller di destinazione, facendo nuovamente clic sullo stesso collegamento ipertestuale invocherà il controller solo una volta.

Non ho ancora trovato una soluzione valida, anche se credo che questo comportamento sia coerente con l’osservazione sollevata da shaunxu , e si spera che questo problema venga risolto nella futura build della nuova libreria di percorsi e insieme alle versioni di AngularJS 1.4.

Nel mio caso, ho trovato due viste usando lo stesso controller.

 $stateProvider.state('app', { url: '', views: { "[email protected]": { controller: 'CtrlOne as CtrlOne', templateUrl: 'main/one.tpl.html' }, "[email protected]": { controller: 'CtrlOne as CtrlOne', templateUrl: 'main/two.tpl.html' } } }); 

Il problema che sto incontrando potrebbe essere tangenziale, ma dato che googling mi ha portato a questa domanda, questo potrebbe essere appropriato. Il problema alza la sua brutta testa per me quando uso UI Router, ma solo quando provo ad aggiornare la pagina con il pulsante di aggiornamento del browser. L’app utilizza l’UI Router con uno stato astratto genitore, quindi i figli vengono esclusi dal genitore. Sulla funzione run() dell’app, c’è un $state.go('...child-state...') . Lo stato genitore usa una resolve e all’inizio pensai che forse un controller figlio è in esecuzione due volte.

Tutto va bene prima che l’URL abbia aggiunto l’hash.
www.someoldwebaddress.org

Quindi una volta che l’url è stato modificato da UI Router,
www.someoldwebaddress.org#/childstate

… e poi quando $stateChangeStart la pagina con il pulsante di aggiornamento del browser , $stateChangeStart si $stateChangeStart due volte e ogni volta punta al childstate .

La resolve sullo stato genitore è ciò che sta sparando due volte.

Forse questo è un kludge; a prescindere, sembra che questo mi elimini il problema: nell’area del codice dove viene prima richiamato $stateProvider , prima controlla se il file window.location.hash è una stringa vuota. Se lo è, tutto è buono; in caso contrario, impostare window.location.hash su una stringa vuota. Quindi sembra che lo $state cerchi di andare da qualche parte una volta piuttosto che due volte.

Inoltre, se non vuoi fare affidamento sull’esecuzione predefinita e state.go(...) , puoi provare ad acquisire il valore hash e utilizzare il valore hash per determinare lo stato figlio in cui ti state.go(...) appena prima dell’aggiornamento della pagina, e aggiungi una condizione all’area nel tuo codice in cui imposti lo state.go(...) .

Nel mio caso è stato a causa del modello di URL che ho usato

il mio url era come / ui / project /: parameter1 /: parameter2.

Non avevo bisogno del paramerter2 in tutti i casi di cambiamento di stato. Nei casi in cui non avevo bisogno del secondo parametro il mio url sarebbe come / ui / project /: parameter1 /. E così ogni volta che ho avuto un cambiamento di stato avrò il mio controller aggiornato due volte.

La soluzione era impostare parametro2 come stringa vuota e fare il cambiamento di stato.

Ho avuto questa doppia inizializzazione per un motivo diverso. Per alcune transizioni di percorso nella mia applicazione, volevo forzare lo scorrimento verso la parte superiore della pagina (ad esempio, nei risultati di ricerca impaginati … cliccando su successivo dovresti portarti all’inizio di pagina 2).

Ho fatto questo aggiungendo un listener al $rootScope $on $viewContentLoaded che (in base a determinate condizioni) eseguito

 $location.hash('top'); 

Inavvertitamente ciò stava facendo rivalutare le mie rotte e reinizializzare i controllori

Il mio problema era l’aggiornamento dei parametri di ricerca come $location.search('param', key);

puoi leggere di più qui

il controller viene chiamato due volte a causa dell’aggiunta dei parametri nell’URL

Nel mio caso, rinominare il controller con un nome diverso ha risolto il problema.

C’è stato un conflitto tra i nomi dei controller con il modulo ” angular -ui-tree “: ho rinominato il mio controller da “CatalogerTreeController” in ” TreeController ” e quindi questo controller inizia a essere avviato due volte nella pagina in cui è stata usata la direttiva ” ui-tree ” perché questa direttiva usa il controller chiamato ” TreeController “.

Ho avuto lo stesso problema e dopo aver provato tutte le risposte ho finalmente trovato che avevo una direttiva a mio avviso che era legata allo stesso controller.

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

Dopo aver rimosso la direttiva, il controller ha smesso di essere chiamato due volte. Ora la mia domanda è, come si può usare questa direttiva legata allo scope del controllore senza questo problema?

Ho appena risolto il mio, che in realtà è stato abbastanza deludente. È un’app ibrida ionica, ho usato ui-router v0.2.13. Nel mio caso c’è un lettore di epub (usando epub.js) che riportava continuamente “nessun documento trovato” quando navigo nella mia biblioteca di libri e seleziono qualsiasi altro libro. Quando ho ricaricato il libro del browser veniva reso perfettamente, ma quando ho selezionato un altro libro ho avuto di nuovo lo stesso problema.

La mia soluzione era molto semplice. Ho appena rimosso il reload:true da $state.go("app.reader", { fileName: fn, reload: true }); nel mio LibraryController

Ho lo stesso problema in [email protected] , e questo perché la barra in più alla fine della regex route:

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

a

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

e funziona correttamente.

Per coloro che usano la syntax ControllerAs, basta dichiarare l’etichetta del controller nel $ routeprovider come segue:

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

o

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

Dopo aver dichiarato $ routeprovider, non fornire il controller come nella vista. Utilizzare invece l’etichetta nella vista.

Ho capito che il mio viene chiamato due volte perché stavo chiamando il metodo due volte dal mio html.

 `

La sezione evidenziata stava causando findX () per essere chiamato due volte. Spero che aiuti qualcuno.