Angularjs, passer la portée entre les routes


87

J'ai une situation avec un formulaire qui s'étend sur plusieurs pages (ce n'est peut-être pas idéal, mais c'est comme ça). J'aimerais avoir une portée pour l'ensemble du formulaire qui se remplit au fur et à mesure, de sorte que si l'utilisateur fait des va-et-vient entre les étapes, il est facile de se souvenir de l'état.

Je dois donc faire, en très pseudo-code:

  1. Ensemble $scope.val = <Some dynamic data>
  2. Cliquez sur un lien et être dirigé vers un nouveau modèle (probablement avec le même contrôleur).
  3. $scope.val devrait toujours avoir la même valeur que sur la dernière page.

Les données persistantes pour la portée sont-elles en quelque sorte la bonne façon de procéder, ou y a-t-il une autre façon? Pouvez-vous même créer un contrôleur qui a une portée persistante entre les routes, sauf pour l'enregistrer dans une base de données bien sûr.


Juste comme un ajout à ganaraj: vous trouvez ici une très belle entrée de blog avec un screencast sur la façon de faire communiquer différents contrôleurs. Il y a aussi quelques jsfiddles utiles avec lesquels jouer. onehungrymind.com/angularjs-communicating-between-controllers J'espère que cela aide.
F Lekschas

Réponses:


138

Vous devez utiliser un service car un service persistera tout au long de la vie de votre application.

Disons que vous souhaitez enregistrer les données relatives à un utilisateur

Voici comment vous définissez le service:

app.factory("user",function(){
        return {};
});

Dans votre premier contrôleur:

app.controller( "RegistrationPage1Controller",function($scope,user){
    $scope.user = user;
    // and then set values on the object
    $scope.user.firstname = "John";
    $scope.user.secondname = "Smith";
});

app.controller( "RegistrationSecondPageController",function($scope,user){
        $scope.user = user;
        // and then set values on the object
        $scope.user.address = "1, Mars";

    });

6
Ahhh! J'ai essayé cela avant mais je n'ai pas pu le faire fonctionner car j'ai utilisé le même contrôleur pour les deux routes, donc à chaque nouvelle route, les valeurs par défaut écraseraient celles que j'ai entrées sur la page précédente. Avec deux contrôleurs, ou sans valeurs par défaut, cela ne se produit plus. Merci!
Erik Honn

1
Qu'en est-il de Value Recipe docs.angularjs.org/guide/providers , comme myApp.value('clientId', 'a12345654321x');est-ce également persistant entre les routes?
The Bndr

@TheBndr: Ça devrait l'être. Les valeurs ne sont qu'une forme particulière de services si je comprends bien.
Robert Koritnik

3
Les services ne conserveront pas les données si vous rechargez la page ... Donc, si vous êtes à la page 4 de votre formulaire et rechargez cette page, vous perdrez toutes les données remplies.
danielrvt

1
Bonne réponse! En complément, un guide de style pour ceux qui adoptent cette réponse - les services qui ne sont pas eux-mêmes des constructeurs (c'est-à-dire utilisés comme nouveau XX) devraient être nommés camel minuscules: github.com/mgechev/angularjs-style-guide .
Matt Byrne

9

Le service fonctionnera, mais une manière logique de le faire en utilisant uniquement des portées et des contrôleurs ordinaires consiste à configurer vos contrôleurs et éléments de manière à ce qu'ils reflètent la structure de votre modèle. En particulier, vous avez besoin d'un élément parent et d'un contrôleur qui établissent une portée parent. Les pages individuelles du formulaire doivent résider dans une vue qui est un enfant du parent. L'étendue parent persiste même lorsque la vue enfant est mise à jour.

Je suppose que vous utilisez ui-router afin que vous puissiez avoir des vues nommées imbriquées. Puis en pseudo-code:

<div ng-controller="WizardController">
  <div name="stepView" ui-view/>
</div>

Ensuite, WizardController définit les variables de portée que vous souhaitez conserver à travers les étapes du formulaire multi-pages (que je qualifie d '«assistant»). Ensuite, vos itinéraires seront mis à jour stepViewuniquement. Chaque étape peut avoir ses propres modèles, contrôleurs et étendues, mais leurs étendues sont perdues de page en page. Mais les étendues de WizardController sont conservées sur toutes les pages.

Pour mettre à jour les étendues WizardController à partir des contrôleurs enfants, vous devez utiliser une syntaxe similaire à celle-ci $scope.$parent.myProp = 'value'ou définir une fonction setMyPropsur WizardController pour chaque variable d'étendue. Sinon, si vous essayez de définir les variables de portée parent directement à partir des contrôleurs enfants, vous finirez par créer simplement une nouvelle variable de portée sur l'enfant lui-même, en ombrant la variable parente.

Un peu difficile à expliquer et je m'excuse pour le manque d'exemple complet. Fondamentalement, vous voulez un contrôleur parent qui établit une portée parent, qui sera préservée sur toutes les pages de votre formulaire.


1
Cela fonctionnerait avec ui-router oui (et c'est une très bonne façon de concevoir une page comme ça), mais pas hors de la boîte. Hors de la boîte, la méthode de service est la voie à suivre.
Erik Honn

1
Juste pour clarifier, les propriétés de la portée parent seront toujours héritées par la portée enfant. Toutefois, si vous souhaitez définir une propriété d'étendue parent à partir de l'étendue enfant, vous devez y accéder sur le parent, sinon vous créez une nouvelle propriété du même nom sur l'étendue enfant. La définition d'une propriété d'étendue parent peut être effectuée en allant:$scope.$parent.myProp = 'hello world';
mbursill

1
C'est une approche beaucoup plus agréable que d'utiliser un service. Les services sont des singletons, donc tout état qui y est défini est global à l'application. Si l'utilisateur quitte l'assistant en cours de route, puis le redémarre, il restera un état résiduel dans le service de l'exécution précédente - à moins que vous ne vous assuriez de nettoyer correctement le service à chaque point de sortie, mais cela peut tout à fait devenir facilement un véritable casse-tête de maintenance!
Dan King

Beaucoup plus désireux de cette réponse
Kurai Bankusu

Les services sont la première chose à penser si vous n'utilisez pas Angular UI Router. Si vous utilisez UI Router, cependant, il a des résolutions imbriquées qui peuvent conserver les informations entre les vues imbriquées. Je pense que ce serait une approche plus propre que d'essayer d'accéder à la portée des parents. medium.com/opinionated-angularjs/…
losmescaleros

5

Les données peuvent être transmises entre les contrôleurs de deux manières

  1. $rootScope
  2. Modèle

L'exemple ci-dessous montre le passage de valeurs à l'aide du modèle

app.js

angular.module('testApp')
  .controller('Controller', Controller)
  .controller('ControllerTwo', ControllerTwo)
  .factory('SharedService', SharedService);

SharedService.js

function SharedService($rootScope){

 return{
    objA: "value1",
    objB: "value2"
  }
}

// Modifier la valeur dans le contrôleur A

Controller.js

function Controller($scope, SharedService){

 $scope.SharedService = SharedService;

 $scope.SharedService.objA = "value1 modified";
}

// Accéder à la valeur dans controllertwo

ControllerTwo.js

function ControllerTwo($scope, SharedService){

 $scope.SharedService = SharedService;

 console.log("$scope.SharedService.objA"+$scope.SharedService.objA); // Prints "value1 modified"
}

J'espère que cela t'aides.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.