angularjs - change - routermodule.forchild example
Alcance y instanciación del controlador con enrutador ui (3)
Estoy confundido acerca de cuándo los controladores se instancian. Además, ¿cómo se crean instancias de los controladores cuando se anidan los estados? Podría confundirme cómo el ámbito se adjunta a la vista y al controlador, es decir, si cada vista tiene su propio controlador y ámbito o comparten el mismo ámbito.
¿Alguien por favor puede explicar cuándo los controladores se instancian? ¿En rutas anidadas todas las vistas comparten un controlador y un alcance? ¿Qué sucede cuando cambio de estado y vuelvo a un estado, otro controlador se crea una instancia?
A continuación se muestran 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''
}
}
})
Los controladores se instancian cada vez que visita el estado específico. Por ejemplo, mientras visita app.pincode.pincodeLogin
por primera vez, se AppController
un AppController
y dos PincodeControllers
, cada uno con su propia vista, asumiendo 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 no se ''app.pincode.settings''
los dos controladores más altos en la jerarquía. Los alcances siguen el patrón de herencia estándar de AngularJS, no están aislados.
Es probable que desee eliminar los controladores en los sub estados (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 instancian cuando las vistas correspondientes se cargan por primera vez.
Por ejemplo, si tiene 3 pestañas asociadas con 3 controladores, entonces el controlador asociado con la vista predeterminada crea una instancia de Primera. A continuación, cuando carga las otras vistas, también se crea una instancia de los controladores asociados.
Pero curiosamente, una vez que se carga una vista en el DOM, se almacena en caché de forma predeterminada. Cuando se navega por una vista, su elemento se deja en el DOM y su alcance se desconecta del ciclo $ watch. Al navegar a una vista que ya está almacenada en caché, su alcance se vuelve a conectar y el elemento existente que se dejó en el DOM se convierte en la vista activa.
Para obtener respuestas aún más detalladas, podemos / debemos observar el código fuente y verificar la documentación . Permítame tratar de explicar las tres preguntas (y también citar del código y el 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 un .state()
como el objeto de views
:
.state(''...'', {
// The view definition
views : {
'''' : {
template: ...
controller: ...
resolve: ..
}
},
resolve: ...
}
Por lo tanto, siempre que la vista (la vista ui-view
) se llena con configuraciones definidas dentro de una vista de estado, actúa casi como una directiva estándar, pero mejorada .
1) Se encuentra la plantilla,
2) Resuelve se resuelve
...
x) el controlador es instanciado ...
Los objetivos ui-view
directivas de ui-view
) podrían usar nombres y podrían llenarse con diferentes estados en la jerarquía.
Podría significar que podría haber un contenido dentro de una vista (por ejemplo, un título ) , definido por el padre y reemplazado por el 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 realicemos la transición entre estos dos estados) :
$state.go(''parent'')
: la vista (plantilla, controlador ...) definida en''title@parent'' : { ...}
se inyectará enui-view="title"
destino y se creará una instancia como se describe encima$state.go(''parent.child'')
- casi lo mismo, solo la vista se tomará de la definición de estado / vista hijo''title'' : { ...}
. Eso reemplazará el contenido deui-view="title"
y se creará una instancia de la manera descrita anteriormente
Esto sucederá cada vez que vayamos de padres a hijos y de niños a padres .
2. ¿En las rutas anidadas, todas las vistas comparten un controlador y un alcance?
Una respuesta simple es NO , no hay un intercambio común.
De hecho, cada controlador tiene su propio alcance , el que se crea desde el alcance de la vista principal. En primer lugar la documentación:
¿Qué heredan los estados infantiles de los estados padres?
...
Herencia de alcance solo por jerarquía de vista
Tenga en cuenta que las propiedades de alcance solo heredan la cadena de estado si las vistas de sus estados están anidadas. La herencia de las propiedades del ámbito 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 totalmente posible que tenga estados anidados cuyas plantillas llenen ui-views en varias ubicaciones no anidadas dentro de su sitio. En este escenario, no puede esperar acceder a las variables de alcance de las vistas del estado principal dentro de las vistas de los estados secundarios.
Entonces, cada vez que nuestro controller
(bueno, la vista con plantilla, controlador ...) se inyecta en el ui-view="..."
destino del padre ui-view="..."
se obtiene el alcance heredado:
newScope = scope.$new();
En pocas palabras, eso significa que los objetos JS (por ejemplo, scope.Model = {}
) se pueden compartir entre el elemento secundario y el principal.
$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 sobre la herencia prototípica aquí:
¿Cuáles son los matices del alcance prototípico / herencia 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 principal (recuerde ui-view="title"
arriba) se reemplaza por la vista secundaria, y luego se vuelve a crear (transición de hijo a padre) - dicho controlador será reinicializado (discutido anteriormente).
Pero cuando hablamos de la vista principal principal (generalmente sin nombre) , que representa la principal (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 vuelve a crear instancias. Vive durante la vida de todos sus hijos, más el de uno de los padres (no se seleccionó el estado del niño) .
Para volver a cargar esta vista / controlador, tenemos que usar una opción de reload
$ state.go (a, params, opciones)
... opciones opciones objeto. Las opciones son:
- ...
- reload -
{boolean=false}
, If true forzará la transición incluso si el estado o los parámetros no han cambiado, es decir, una recarga del mismo estado. Se diferencia de reloadOnSearch porque utilizarías esto cuando quieras forzar una recarga cuando todo es igual, incluidos los parámetros de búsqueda.
Espero que esto ayude un poco. Para más información, echa un vistazo a estos recursos:
- Estados anidados y vistas anidadas
- Múltiples vistas con nombre
- Referencia API
- State.js de la aplicación de ejemplo : diría que el mejor código documentado de todos los tiempos