¿Cómo comparto datos de $scope entre estados en angularjs ui-router?

Resuelto sjt003 asked hace 9 años • 5 respuestas

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.

sjt003 avatar Dec 30 '14 04:12 sjt003
Aceptado

Creé un plunker funcional , mostrando cómo usar $scopeun 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 viewde cada estado obtiene new una instancia de definido controller. Entonces, si bien tenemos mainControlleralgo 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.Modelya 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-Routervistas y ámbitos angulares, y debido a que usamos inteligentemente un tipo de referencia ( Model), es decir, tenemos '.'un punto en ng-modella definición, ahora podemos compartir datos.

NOTA: tener el punto '.' simplemente ng-model="Model.PropertyNamesignifica que hay un referenceobjeto Model {}con alguna propiedad:PropertyName

Consulte el ejemplo de trabajo aquí

Radim Köhler avatar Dec 30 '2014 05:12 Radim Köhler

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 dataelemento en cada ruta.
  • El abstractestado tiene SignupController. Ese es el único controlador para este formulario de varios pasos. No abstractes 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 $statey 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.

Michael Cole avatar Apr 06 '2015 09:04 Michael Cole