¿Cómo comparto datos de $scope entre estados en angularjs ui-router?
Sin utilizar un servicio o construir observadores en el controlador principal, ¿cómo se podría dar a los niños acceso a los estados del controlador principal $scope
?
.state("main", {
controller:'mainController',
url:"/main",
templateUrl: "main_init.html"
})
.state("main.1", {
controller:'mainController',
parent: 'main',
url:"/1",
templateUrl: 'form_1.html'
})
.state("main.2", {
controller:'mainController',
parent: 'main',
url: "/2",
templateUrl: 'form_2.html'
})
No puedo acceder al alcance de mainController en estado secundario, o más bien estoy obteniendo otra instancia de ese alcance, no es lo que quiero. Siento que me falta algo simple. Hay una opción de configuración de datos compartidos en el objeto de estado, pero no estoy seguro de si debería usarse para algo como esto.
Creé un plunker funcional , mostrando cómo usar $scope
un UI-Router.
La definición del estado no ha cambiado:
$stateProvider
// States
.state("main", {
controller:'mainController',
url:"/main",
templateUrl: "main_init.html"
})
.state("main.1", {
controller:'mainController',
parent: 'main',
url:"/1",
templateUrl: 'form_1.html'
})
.state("main.2", {
controller:'mainController',
parent: 'main',
url: "/2",
templateUrl: 'form_2.html'
})
Pero cada estado puede tener un controlador diferente. ¿Por qué? porque cada uno view
de cada estado obtiene new
una instancia de definido controller
. Entonces, si bien tenemos mainController
algo como el siguiente, podemos estar seguros de que si navegamos hasta el estado, 'main.2'
se creará una instancia dos veces.
controller('mainController', function ($scope) {
$scope.Model = $scope.Model || {Name : "xxx"};
})
Pero lo que podemos ver aquí es que verificamos si $scope.Model
ya existe... y si no (estado principal) , lo instanciamos con una nueva instancia {Name : "xxx"}
.
Bueno, lo que estoy diciendo es: sólo el estado padre iniciará el archivo $scope.Model
. Todos los demás ya lo tendrán lleno. ¿Cómo? Bueno aquí está la respuesta:
Herencia de alcance solo por jerarquía de vistas
Tenga en cuenta que las propiedades de alcance solo se heredan en la cadena de estados si las vistas de sus estados están anidadas. La herencia de propiedades de alcance no tiene nada que ver con el anidamiento de sus estados y sí con el anidamiento de sus vistas (plantillas).
Es muy posible que tenga estados anidados cuyas plantillas completen vistas de interfaz de usuario 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, como se indica en la documentación. Debido a que nuestras vistas secundarias están anidadas en la vista principal, el alcance se hereda.
Comprender los alcances
En AngularJS, un ámbito secundario normalmente hereda de forma prototípica de su ámbito principal.
...Teniendo un '.' en sus modelos garantizará que la herencia prototípica esté en juego.
// So, use
<input type="text" ng-model="someObj.prop1">
// rather than
<input type="text" ng-model="prop1">.
Y eso es. Obtenemos herencia de UI-Router
vistas y ámbitos angulares, y debido a que usamos inteligentemente un tipo de referencia ( Model
), es decir, tenemos '.'
un punto en ng-model
la definición, ahora podemos compartir datos.
NOTA: tener el punto '.' simplemente ng-model="Model.PropertyName
significa que hay un reference
objeto Model {}
con alguna propiedad:PropertyName
Consulte el ejemplo de trabajo aquí
Puede obtener el alcance completo a través de $rootScope . Si necesita solo una parte del alcance, ui-router tiene una función de datos personalizados .
A continuación se explica cómo crear un formulario de varios pasos. Necesitaba que las rutas contuvieran información sobre sus pasos en el flujo.
Primero, tengo algunas rutas con UI-router:
// Sign UP routes
.state('sign-up', {
abstract: true,
url: '/sign-up',
controller: 'SignupController',
templateUrl: 'sign-up/index.html',
})
.state('sign-up.start', {
url: '-start',
templateUrl: 'sign-up/sign-up.start.html',
data: { step: 0, title: 'Welcome to Mars!', },
})
.state('sign-up.expertise', {
url: '-expertise',
templateUrl: 'sign-up/sign-up.expertise.html',
data: { step: 1, title: 'Your Expertise'},
})
Aviso:
- el
data
elemento en cada ruta. - El
abstract
estado tieneSignupController
. Ese es el único controlador para este formulario de varios pasos. Noabstract
es obligatorio, pero tiene sentido para este caso de uso.
SignupController.js
angular.module('app').controller('SignupController', function($scope, $state) {
$scope.state = $state;
});
Aquí conseguimos el ui-router $state
y lo ponemos.$scope
Aquí está la plantilla principal 'sign-up/index.html':
<h2>{{state.current.data.title}}</h2>
<div>This is a multi-step-progress control {{state.current.data.step}}</div>
<form id="signUpForm" name="signUpForm" novalidate>
<div ui-view></div>
</form>
Las plantillas secundarias pueden ser las que quieran.