Lucha contra el controlador de ejecución AngularJS dos veces

Entiendo que AngularJS corre a través de un código dos veces, a veces incluso más, como eventos de $watch , comprobando constantemente los estados del modelo, etc.

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

Se ejecuta dos veces, insertando 2 registros en mi base de datos. ¡Claramente sigo aprendiendo ya que he estado golpeando mi cabeza contra esto por años!

El enrutador de la aplicación especificó la navegación a MyController así:

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

Pero también tuve esto en home.html :

 

Esto digirió el controlador dos veces. La eliminación del atributo data-ng-controller del HTML resolvió el problema. Alternativamente, el controller: propiedad podría haberse eliminado de la directiva de enrutamiento.

Este problema también aparece cuando se usa navegación con tabs. Por ejemplo, app.js puede contener:

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

La pestaña de informes correspondiente HTML podría parecerse a:

   

Esto también dará como resultado ejecutar el controlador dos veces.

AngularJS docs – ngController
Tenga en cuenta que también puede adjuntar controladores al DOM al declararlo en una definición de ruta a través del servicio $ route. Un error común es declarar nuevamente el controlador usando ng-controller en la plantilla misma. Esto hará que el controlador se adjunte y ejecute dos veces.

Cuando utiliza ngRoute con la directiva ng-view , el controlador se adjunta a ese elemento dom de forma predeterminada (o ui-view si usa ui-router). Por lo tanto, no será necesario volver a adjuntarlo en la plantilla.

Acabo de pasar por esto, pero el problema era diferente de la respuesta aceptada. Realmente estoy dejando esto aquí para mi yo futuro, para incluir los pasos que pasé para solucionarlo.

  1. Eliminar declaraciones de controlador redundantes
  2. Verificar barras inclinadas en las rutas
  3. Comprobar ng-ifs
  4. Verifique si hay envolvimiento innecesario ng-view llamadas ng-view (accidentalmente me había quedado en una ng-view que estaba envolviendo mi actual ng-view . Esto dio como resultado tres llamadas a mis controladores).
  5. Si está en Rails, debe eliminar la gem turbolinks del archivo application.js . Perdí todo un día para descubrir eso. Encontrado respuesta aquí .
  6. Inicializando la aplicación dos veces con ng-app y con bootstrap. Lucha contra el controlador de ejecución AngularJS dos veces
  7. Cuando se usa $ compile en un elemento completo en la función ‘enlace’ de la directiva que también tiene su propio controlador definido y usa devoluciones de llamada de este controlador en la plantilla a través de ng-clic, etc. Encontré la respuesta aquí .

Solo quiero agregar un caso más cuando el controlador puede iniciar dos veces (esto es real para angular.js 1.3.1):

 
Loading...

En este caso $ route.current ya estará configurado cuando ng-view inicie. Eso causa inicialización doble.

Para solucionarlo, simplemente cambie ng-if a ng-show / ng-hide y todo funcionará bien.

Me gustaría agregar como referencia:

La ejecución del código del controlador doble también puede ser causada al hacer referencia al controlador en una directiva que también se ejecuta en la página.

p.ej

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

Cuando también tienes ng-controller = “myController” en tu HTML

Al usar angular-ui-router con Angular 1.3+, hubo un problema sobre la representación de vistas dos veces en la transición de la ruta . Esto dio como resultado la ejecución de controladores dos veces también. Ninguna de las soluciones propuestas funcionó para mí.

Sin embargo, la actualización angular-ui-router de 0.2.11 a 0.2.13 resolvió el problema para mí.

Rompí mi aplicación y todas sus dependencias en pedazos sobre este tema (detalles aquí: la aplicación AngularJS inicia dos veces (intentó las soluciones habituales …) )

Y al final, todo fue culpa del complemento Batarang Chrome.

Resolución en esta respuesta :

Recomiendo encarecidamente que lo primero en la lista de cualquier persona es deshabilitarla por correo antes de alterar el código.

Tuve el mismo problema, en una aplicación simple (sin enrutamiento y una simple referencia de controlador ng) y el constructor de mi controlador se ejecutó dos veces. Finalmente, descubrí que mi problema era la siguiente statement de autoarranque de mi aplicación AngularJS en mi vista Razor

  

También lo he bootstrapé manualmente usando angular.bootstrap ie

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

así que quitar uno de ellos, funcionó para mí.

Si sabe que su controlador se está ejecutando involuntariamente más de una vez, intente buscar a través de sus archivos el nombre del controlador ofensor, por ejemplo: search: MyController a través de todos los archivos. Es probable que haya sido copiado en otro archivo html / js y se olvidó de cambiarlo cuando desarrolló o usó esos parciales / controladores. Fuente: cometí este error

En algunos casos, su directiva se ejecuta dos veces cuando simplemente no corrige cerca de su directiva de esta manera:

Some content

Esto ejecutará su directiva dos veces. También hay otro caso frecuente cuando su directiva se ejecuta dos veces:

¡asegúrese de no incluir su directiva en su index.html TWICE !

Me he estado rascando la cabeza por este problema con AngularJS 1.4 rc build, y luego me di cuenta de que ninguna de las respuestas anteriores era aplicable ya que se originó a partir de la nueva biblioteca de enrutadores para Angular 1.4 y Angular 2 en el momento de escribir estas líneas. Por lo tanto, voy a dejar caer una nota aquí para cualquier persona que pueda estar utilizando la nueva biblioteca de rutas Angular.

Básicamente, si una página html contiene una directiva ng-viewport para cargar partes de su aplicación, al hacer clic en un hipervínculo especificado en ng-link , el controlador objective del componente asociado se cargará dos veces. La sutil diferencia es que, si el navegador ya ha cargado el controlador objective, al volver a hacer clic en el mismo hipervínculo solo invocará el controlador una vez.

Aún no he encontrado una solución viable, aunque creo que este comportamiento es consistente con la observación planteada por shaunxu , y espero que este problema se resuelva en la futura comstackción de la nueva biblioteca de rutas y junto con las versiones de AngularJS 1.4.

En mi caso, encontré dos vistas usando el mismo 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' } } }); 

El problema que estoy enfrentando puede ser tangencial, pero como Google me llevó a esta pregunta, podría ser apropiado. El problema me sale mal cuando uso el Router UI, pero solo cuando bash actualizar la página con el botón de actualización del navegador. La aplicación utiliza el enrutador UI con un estado abstracto padre, y luego el hijo establece el padre. En la función de run() aplicaciones run() , hay un $state.go('...child-state...') . El estado padre usa una resolve , y al principio pensé que tal vez un controlador secundario se está ejecutando dos veces.

Todo está bien antes de que la URL tenga el hash adjunto.
www.someoldwebaddress.org

Luego, una vez que la URL ha sido modificada por UI Router,
www.someoldwebaddress.org#/childstate

… y luego, cuando actualizo la página con el botón de actualización del navegador , $stateChangeStart dispara dos veces, y cada vez apunta al estado de los childstate .

La resolve en el estado principal es lo que se dispara dos veces.

Tal vez esto es un obstáculo; independientemente, esto parece eliminar el problema para mí: en el área de código donde $stateProvider se invoca por primera vez , primero verifique si window.location.hash es una cadena vacía. Si es así, todo está bien; si no lo está, configure la ventana.location.hash en una cadena vacía. Entonces parece que el $state solo intenta ir a alguna parte una vez en lugar de dos.

Además, si no quiere confiar en la run predeterminada de la aplicación y state.go(...) , puede intentar capturar el valor hash y usar el valor hash para determinar el estado secundario en el que estaba antes de actualizar la página. y agregue una condición al área en su código donde establece state.go(...) .

En mi caso fue por el patrón de URL que utilicé

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

No necesitaba paramerter2 en todos los casos de cambio de estado. En los casos en que no necesitaba el segundo parámetro mi URL sería / ui / project /: parameter1 /. Y cada vez que tuve un cambio de estado, mi controlador se actualizará dos veces.

La solución fue establecer el parámetro2 como una cadena vacía y hacer el cambio de estado.

He tenido esta doble inicialización por una razón diferente. Para algunas transiciones de ruta en mi aplicación, quería forzar el desplazamiento hasta casi la parte superior de la página (por ejemplo, en los resultados de búsqueda paginados … al hacer clic en Siguiente debería acceder a la parte superior de la página 2).

Hice esto agregando un oyente al $rootScope $on $viewContentLoaded que (según ciertas condiciones) se ejecutó

 $location.hash('top'); 

Inadvertidamente, esto estaba causando que mis rutas se reevaluaran y los controladores se reiniciaran

Mi problema era actualizar los parámetros de búsqueda como $location.search('param', key);

Puedes leer más sobre esto aquí

controlador que se llama dos veces debido a agregar params en url

En mi caso, el cambio de nombre del controlador a un nombre diferente resolvió el problema.

Hubo un conflicto entre los nombres de los controladores con el módulo ” angular-ui-tree “: renombré mi controlador de “CatalogerTreeController” a ” TreeController ” y luego este controlador comienza a iniciarse dos veces en la página donde se usa la directiva ” ui-tree ” porque esta directiva usa un controlador llamado ” TreeController “.

Tuve el mismo problema y después de probar todas las respuestas finalmente encontré que tenía una directiva en mi opinión que estaba vinculada al mismo controlador.

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

Después de eliminar la directiva, el controlador dejó de llamarse dos veces. Ahora mi pregunta es, ¿cómo puede usar esta directiva vinculada al scope del controlador sin este problema?

Acabo de resolver el mío, que en realidad fue bastante decepcionante. Es una aplicación híbrida iónica. He usado ui-router v0.2.13. En mi caso, hay un lector de epub (que usa epub.js) que informaba continuamente “no se encontró ningún documento” una vez que navego a la biblioteca de mis libros y selecciono cualquier otro libro. Cuando volví a cargar, el libro del navegador se estaba procesando perfectamente, pero cuando seleccioné otro, volví a tener el mismo problema.

Mi solución fue muy simple. Acabo de eliminar la reload:true de $state.go("app.reader", { fileName: fn, reload: true }); en mi LibraryController

Tengo el mismo problema en angular-route@1.6.7 , y es porque la barra extra en el final de la ruta de expresión regular:

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

a

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

y funciona correctamente

Para aquellos que usan la syntax de ControllerAs, simplemente declare la etiqueta del controlador en $ routeprovider de la siguiente manera:

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

o

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

Después de declarar el $ routeprovider, no suministre el controlador como en la vista. En su lugar, use la etiqueta en la vista.

Descubrí que el mío es llamado dos veces porque lo llamé dos veces desde mi html.

 `

La sección resaltada causaba que findX () se llamara dos veces. Espero que ayude a alguien.