instanciación de scope y controlador con enrutador ui

Estoy confundido acerca de cuándo se crean instancias de los controladores. Además, ¿cómo se instancian los controladores cuando se anidan los estados? Me puede confundir cómo se adjunta el scope para ver y el controlador, es decir, si cada vista tiene su propio controlador y scope o si comparten el mismo scope.

¿Puede alguien explicar por favor cuándo se crean instancias de los controladores? En rutas anidadas, ¿todas las vistas comparten un controlador y scope? ¿Qué sucede cuando cambio de estado y vuelvo a un estado? ¿Se crea una instancia de otro controlador?

A continuación están mis rutas (archivo de configuración):

.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) -> $stateProvider .state('app', { url: '/app', abstract: true, templateUrl: 'templates/menu.html', controller: 'AppController' }) .state('app.pincode', { url: '/pincode', views: { menuContent: { templateUrl: 'templates/pincode-yield.html', controller: 'PincodeController' } } }) .state('app.pincode.create', { url: '/create', views: { pincode: { templateUrl: 'templates/pincode-create.html', controller: 'PincodeController' } } }) .state('app.pincode.pincodeLogin', { url: '/login', views: { pincode: { templateUrl: 'templates/pincode-login.html', controller: 'PincodeController' } } }) .state('app.pincode.settings', { url: '/settings', views: { pincode: { templateUrl: 'templates/settings.html', controller: 'PincodeController' } } }) 

Para obtener respuestas aún más detalladas, podemos / debemos observar el código fuente y verificar la documentación . Permítanme intentar explicar las tres preguntas (y también citar de código y documento).

1. ¿Cuándo se crean instancias de los controladores?

Aquí podemos observar el código de la directiva ui-view :

[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]

Los controladores están relacionados con las vistas . Esas views , que se definen dentro de .state() como el objeto de views :

 .state('...', { // The view definition views : { '' : { template: ... controller: ... resolve: .. } }, resolve: ... } 

Entonces, cada vez que view ( ui-view ) se llena con configuraciones definidas dentro de una vista de estado, actúa casi como una directiva estándar pero mejorada .

1) Plantilla se encuentra,
2) Se resuelven los problemas

x) El controlador está instanciado …

Los objectives ui-view directivas de ui-view ) podrían usar nombres, y podrían llenarse por diferentes estados en la jerarquía.

Podría significar que podría haber contenido dentro de una vista (por ejemplo, título ) , definido por los padres y reemplazado por un niño

 // parent .state('parent', { views : { '' : {...} // the main parent view, with ui-view="title" 'title@parent' : { ...} // here we go and fill parent's ui-view="title" }, ... } // child .state('parent.child', { views : { 'title' : { ...} // here we change the parent's target ui-view="title" }, ... } 

La definición de estado anterior hará (siempre que hagamos una transición entre estos dos estados) hacer:

  • El $state.go('parent') – la vista (plantilla, controlador …) definida en 'title@parent' : { ...} se inyectará en el destino ui-view="title" y se creará una instancia como se describe encima

  • $state.go('parent.child') : casi lo mismo, solo la vista se tomará del estado hijo / definición de la vista 'title' : { ...} . Eso reemplazará el contenido de ui-view="title" y se instanciará como se describió anteriormente

Esto sucederá cada vez que vayamos de padres a hijos y de hijos a padres .

2. En rutas anidadas, ¿todas las vistas comparten un controlador y scope?

Una respuesta simple es NO , no hay intercambio común.

De hecho, cada controlador tiene su propio scope , el que se crea desde el ámbito de vista principal. En primer lugar, la documentación:

¿Qué heredan los estados secundarios de los estados padres?

Herencia de scope solo por jerarquía de vistas

Tenga en cuenta que las propiedades del scope solo heredan en la cadena de estado si las vistas de sus estados están anidadas. La herencia de las propiedades del scope no tiene nada que ver con la anidación de sus estados y todo lo relacionado con la anidación de sus vistas (plantillas).

Es muy posible que haya nested estados cuyas plantillas llenan vistas de ui en varias ubicaciones no anidadas dentro de su sitio. En este escenario, no puede esperar acceder a las variables de ámbito de las vistas de estado primario dentro de las vistas de los estados secundarios.

Entonces, cada vez que nuestro controller (y la vista con plantilla, controlador …) se inyecta en el destino ui-view="..." del padre ui-view="..." obtiene el scope heredado:

 newScope = scope.$new(); 

Eso en pocas palabras significa que los objetos JS (p scope.Model = {} Ej. scope.Model = {} ) se pueden compartir entre hijos y padres.

 $scope.Model.id = 1; // will refer to the same id in both parent & child 

Sin embargo , los tipos básicos de Javascript no se pasan por referencia, por lo que sus valores no se sincronizan automáticamente entre los ámbitos:

 // set in parent $scope.id = 1; // in child after inherted still === 1 $scope.id = 2; // now 2 for a child, different value in parent - still === 1 

Vale la pena leer más acerca de la herencia prototípica aquí:
¿Cuáles son los matices del scope de la herencia prototípica / prototípica en AngularJS?

3. ¿Qué sucede cuando cambio de estado y vuelvo a un estado? ¿Se crea una instancia de otro controlador?

Depende.

Si la vista secundaria (recuerde ui-view="title" arriba) se reemplaza por vista secundaria, y luego se vuelve a crear (transición de hijo a principal) – dicho controlador se reinicializará (discutido anteriormente).

Pero cuando hablamos de la vista padre principal (generalmente sin nombre) , que representa el padre (por ejemplo, la vista sin nombre a continuación con el controlador ‘ParentMainCtrl’)

 .state('parent', { views : { '' : { // // the main parent view controller: 'ParentMainCtrl', } 'title@parent' 'tooltip@parent' }, 

Entonces podemos estar seguros de que dicho controlador NO se volverá a instanciar. Vive durante la vida de todos sus hijos, más el de uno de los padres (no se selecciona ningún estado de niño) .

Para volver a cargar esta vista / controlador, tenemos que usar una opción de reload

$ state.go (a, params, opciones)

… opciones Opciones de objeto. Las opciones son:

  • reload{boolean=false} , If true forzará la transición incluso si el estado o params no han cambiado, también conocido como una recarga del mismo estado. Difiere de reloadOnSearch porque lo usaría cuando desee forzar una recarga cuando todo sea igual, incluidos los parámetros de búsqueda.

Espero que esto ayude un poco. Para obtener más información, consulte estos recursos:

  • Estados nesteds y vistas anidadas
  • Múltiples vistas nombradas
  • Referencia de API
  • State.js de la aplicación de muestra : diría que es la pieza de código mejor documentada

Los controladores se instancian cada vez que visita el estado específico. Por ejemplo, al visitar app.pincode.pincodeLogin por primera vez se AppController un AppController y dos PincodeControllers , cada uno con su propia vista, suponiendo que tiene las plantillas correctas. Cambiar a 'app.pincode.settings' destruiría el controlador más interno y lo reemplazaría por uno nuevo, aunque los dos controladores superiores en la jerarquía no se tocarán. Los ámbitos siguen el patrón de herencia estándar de AngularJS, no están aislados.

Probablemente desee eliminar los controladores en los estados secundarios (y manejar la lógica de negocios en el controlador principal) o tener un controlador distinto para cada estado: el mismo controlador para diferentes plantillas y vistas suele ser un signo de mal diseño.

Los controladores se crean instancias cuando se cargan las vistas correspondientes por primera vez.

Por ejemplo, si tiene 3 tabs asociadas con 3 controladores, entonces el controlador asociado con la vista predeterminada instancia primero. A continuación, cuando carga las otras vistas, los controladores asociados también se instancian.

Pero, curiosamente, una vez que se carga una vista en el DOM, se almacena en caché por defecto. Cuando se navega desde una vista, su elemento se deja en el DOM, y su scope se desconecta del ciclo $ watch. Cuando navega hacia una vista que ya está en la memoria caché, su scope se vuelve a conectar y el elemento existente que quedó en el DOM se convierte en la vista activa.