web-dev-qa-db-fra.com

Comment partager des données $ scope entre des états dans angularjs ui-router?

Sans utiliser un service ou créer des observateurs dans le contrôleur parent, comment donner aux États enfants l'accès aux $scope du contrôleur principal.

  .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'
  })  

Je ne peux pas accéder à la portée de mainController dans un état enfant - ou plutôt, je reçois une autre instance de cette portée - pas ce que je veux. Je sens que je manque quelque chose de simple. Il y a une option de configuration de données partagées dans l'objet state, mais je ne suis pas sûr si cela devrait être utilisé pour quelque chose comme ça.

71
sjt003

I plunker de travail créé , montrant comment utiliser _$scope_ et UI-Router.

La définition de l'état est inchangée:

_$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'
  })  
_

Mais chaque état peut avoir un contrôleur différent. Pourquoi? parce que chaque view de chaque état obtient new instance de controller défini. Ainsi, bien que nous ayons mainController comme celui ci-dessous, nous pouvons être sûrs que si nous passons à l'état _'main.2'_, il sera instancié deux fois.

_controller('mainController', function ($scope) {
  $scope.Model = $scope.Model || {Name : "xxx"};
})
_

Mais ce que nous pouvons voir ici , c’est que nous vérifions si _$scope.Model_ existe déjà ... et si non (État parent) nous instancions il avec nouvelle intance {Name : "xxx"}.

Eh bien, ce que je dis, c’est que seul l’État parent initiera le _$scope.Model_. Tous les autres obtiendront cela déjà rempli. Comment? Eh bien voici la réponse:

héritage de la portée par la hiérarchie de vues uniquement

Gardez à l'esprit que les propriétés de portée n'héritent en aval de la chaîne d'états que si les vues de vos états sont imbriquées. L'héritage des propriétés de portée n'a rien à voir avec l'imbrication de vos états et tout ce qui a trait à l'imbrication de vos vues (modèles).

Il est tout à fait possible que vous ayez des états imbriqués dont les modèles remplissent des vues UI à divers emplacements non imbriqués de votre site. Dans ce scénario, vous ne pouvez pas vous attendre à accéder aux variables d'étendue des vues d'état parent dans les vues d'états enfants.

Donc, comme indiqué dans la documentation. Comme nos vues enfant sont imbriquées dans la vue parent, la portée est héritée.

Comprendre les portées

Dans AngularJS, une portée enfant hérite normalement de sa portée parent de manière prototypique.
...

Avoir un '.' dans vos modèles garantira que l’héritage prototype est en jeu.

_// So, use
<input type="text" ng-model="someObj.prop1"> 
// rather than
<input type="text" ng-model="prop1">.
_

Et c'est tout. Nous obtenons l'héritage de _UI-Router_ views et de angular scopes, et parce que nous avons intelligemment utilisé un type de référence (Model), c'est-à-dire que vous avez _'.'_ point dans _ng-model_ définition - nous pouvons partager des données maintenant

NOTE: avoir un point '.' dans _ng-model="Model.PropertyName_ signifie simplement qu'il existe un objet reference _Model {}_ avec une propriété: PropertyName

Vérifiez le exemple de travail ici

107
Radim Köhler

Vous pouvez obtenir la totalité de la portée via $ rootScope . Si vous n'avez besoin que d'une partie de la portée, ui-router a une fonctionnalité données personnalisées .

Voici comment faire un formulaire en plusieurs étapes. J'avais besoin que les routes contiennent des informations sur leurs étapes dans le flux.

Tout d'abord, j'ai quelques itinéraires avec 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'},
  })

Remarquer:

  • l'élément data dans chaque route.
  • L'état abstract a SignupController. C'est le seul contrôleur pour ce formulaire en plusieurs étapes. La abstract n'est pas obligatoire, mais convient à ce cas d'utilisation.

SignupController.js

angular.module('app').controller('SignupController', function($scope, $state) {
  $scope.state = $state;
});

Ici nous obtenons $state de ui-router et le plaçons sur $scope

Voici le modèle 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>

Les modèles enfants peuvent être ce qu'ils veulent.

15
Michael Cole

L'idée est que vous utilisiez scope dans parent-> héritage enfant:

 .state("main", {
      controller:'mainController',
      abstract: true,
      url:"/main",
      templateUrl: "main_init.html"
  })  
  .state("main.1", {
      controller:'mainController1',
      parent: 'main',
      url:"/1",
      templateUrl: 'form_1.html'
  })  
  .state("main.2", {
      controller:'mainController2',
      parent: 'main',
      url: "/2",
      templateUrl: 'form_2.html'
  })  

Alors que l'utilisation est simple, vous avez 3 contrôleurs, l'un est partagé (mainController) et chaque vue a sa propre.

9
Ben Diamant

Si vous utilisez des vues imbriquées, n'écrivez aucun autre contrôleur. De cette manière, ils partageront les mêmes données de contrôleur.

.state("main", {
            url: "/main",
            templateUrl: "templates/Ders",
            controller: "DersController as DersC"
       }).state("main.child1", {
            url: "/child1",
            templateUrl: "templates/Ders/child1"
       }).state("main.child2", {
            url: "/child2",
            templateUrl: "templates/Ders/child2"
        })
7
Bahtiyar Özdere

La solution la plus simple n'est-elle pas de regrouper des variables partagées dans un service auquel vous pouvez accéder dans chaque contrôleur? ...

1
hugsbrugs