430 votes

Comment transmettre des données aux composants routés d'Angular ?

Dans l'un des modèles de mes routes Angular 2 ( FirstComponent ) J'ai un bouton

premier.composant.html

<div class="button" click="routeWithData()">Pass data and route</div>

Mon objectif est à réaliser :

Clic sur un bouton -> acheminement vers un autre composant tout en préservant les données et sans utiliser l'autre composant comme directive.

C'est ce que j'ai essayé...

1ÈRE APPROCHE

Dans la même vue, je stocke les mêmes données basées sur l'interaction de l'utilisateur.

premier.composant.ts

export class FirstComponent {
     constructor(private _router: Router) { }

     property1: number;
     property2: string;
     property3: TypeXY; // this a class, not a primitive type

    // here some class methods set the properties above

    // DOM events
    routeWithData(){
         // here route
    }
}

Normalement, je me dirigerais vers SecondComposant par

 this._router.navigate(['SecondComponent']);

en transmettant éventuellement les données par

 this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);

alors que la définition du lien avec les paramètres serait

@RouteConfig([
      // ...
      { path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent} 
)]

Le problème avec cette approche est que je pense Je ne peux pas transmettre des données complexes (par exemple, un objet comme la propriété3) in-url ;

2IÈME APPROCHE

Une alternative serait d'inclure SecondComponent en tant que directive dans FirstComponent.

  <SecondComponent [p3]="property3"></SecondComponent>

Cependant, je veux itinéraire à ce composant, et non l'inclure !

3IÈME APPROCHE

La solution la plus viable que je vois ici serait d'utiliser une Service (par exemple, FirstComponentService) à l'adresse suivante

  • magasin les données (_firstComponentService.storeData()) sur routeWithData() dans FirstComponent
  • récupérer les données (_firstComponentService.retrieveData()) en ngOnInit() sur SecondComposant

Bien que cette approche semble parfaitement viable, je me demande si c'est le moyen le plus simple / le plus élégant d'atteindre l'objectif.

D'une manière générale, j'aimerais savoir si je manque d'autres approches potentielles pour transmettre les données entre les composants, notamment avec le moins de code possible

4 votes

Merci @Prashobh. Pass data using Query Parameters c'est ce que je cherchais. votre enlace a sauvé ma journée.

0 votes

Angular 7.2 dispose désormais d'une nouvelle fonctionnalité permettant de transmettre des données entre les routes à l'aide de la fonction state vérifier le PR pour plus de détails. Quelques informations utiles aquí

0 votes

@Prashobh Merci beaucoup. Le lien que vous avez partagé est très utile

310voto

Günter Zöchbauer Points 21340

mise à jour 4.0.0

Voir la documentation d'Angular pour plus de détails https://angular.io/guide/router#fetch-data-before-navigating

original

L'utilisation d'un service est la meilleure solution. Dans les paramètres de la route, vous ne devez transmettre que les données que vous souhaitez voir apparaître dans la barre d'URL du navigateur.

Voir aussi https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#servicebidirectionnel

Le routeur livré avec la RC.4 réintroduit les éléments suivants data

constructor(private route: ActivatedRoute) {}

const routes: RouterConfig = [
  {path: '', redirectTo: '/heroes', pathMatch : 'full'},
  {path : 'heroes', component : HeroDetailComponent, data : {some_data : 'some value'}}
];

class HeroDetailComponent {
  ngOnInit() {
    this.sub = this.route
      .data
      .subscribe(v => console.log(v));
  }

  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}

Voir aussi le Plunker à https://github.com/angular/angular/issues/9757#issuecomment-229847781

0 votes

Merci pour la réponse. J'ai jeté un coup d'œil à la documentation. Pouvez-vous préciser quand je dois opter pour les observables et quand je dois simplement définir les attributs à l'aide d'une méthode set/get dans le service ?

0 votes

Les observables permettent aux composants intéressés de s'abonner aux changements. Avec les propriétés, vous devez interroger ( {{myService.someProp}} est reconnu et mis à jour par la détection des changements d'Angulars). Si vous voulez passer à la méthode beaucoup plus performante OnPush stratégie de détection des changements Observables ont un fort avantage car votre code dépend alors d'être notifié des changements afin que votre code puisse invoquer la détection des changements.

4 votes

Cette réponse est-elle toujours valable pour Angular 2.1.0 ?

83voto

Utpal Kumar Das Points 598

Je pense que puisque nous n'avons pas $rootScope Nous pouvons utiliser le service/la classe partagé(e) d'angular 2 alors qu'en angular 1.x. ngOnDestroy transmettre les données au service et, après le routage, récupérer les données du service dans la base de données. ngOnInit fonction :

Ici, j'utilise DataService pour partager l'objet héros :

import { Hero } from './hero';
export class DataService {
  public hero: Hero;
}

Passer l'objet du premier composant de la page :

 ngOnDestroy() {
    this.dataService.hero = this.hero; 
 }

Prenez l'objet du composant de la deuxième page :

 ngOnInit() {
    this.hero = this.dataService.hero; 
 }

Voici un exemple : plunker

0 votes

C'est magnifique, mais est-ce courant dans la communauté Ng2 ? Je ne me souviens pas l'avoir lu dans la documentation...

1 votes

Comparé à d'autres options comme les paramètres url ou le stockage dans le navigateur, cela me semble mieux. Je n'ai pas non plus vu dans la documentation que cela fonctionne de cette manière.

3 votes

Cela fonctionne-t-il lorsque l'utilisateur ouvre un nouvel onglet et qu'il copie-colle la deuxième route du composant ? Puis-je récupérer this.hero = this.dataService.hero ? Est-ce que j'obtiendrai les valeurs ?

50voto

<div class="button" click="routeWithData()">Pass data and route</div>

la façon la plus simple de le faire dans angular 6 ou d'autres versions, je l'espère, est de définir simplement votre chemin avec la quantité de données que vous voulez passer.

{path: 'detailView/:id', component: DetailedViewComponent}

comme vous pouvez le voir dans la définition de mes routes, j'ai ajouté l'élément /:id pour se tenir aux données que je veux transmettre au composant via la navigation par routeur. Par conséquent, votre code ressemblera à

<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>

afin de lire le id sur le composant, il suffit d'importer ActivatedRoute comme

import { ActivatedRoute } from '@angular/router'

et sur le ngOnInit est l'endroit où vous récupérez les données

ngOnInit() {
       this.sub = this.route.params.subscribe(params => {
        this.id = params['id'];
        });
        console.log(this.id);
      }

vous pouvez en savoir plus dans cet article https://www.tektutorialshub.com/angular-passing-parameters-to-route/

26 votes

Que faire si je veux envoyer un objet complexe ? je ne veux pas gonfler mes routes avec des absurdités impossibles à maintenir :(

2 votes

@cmxl Utilisez un service partagé alors.

0 votes

@cmxl L'idée d'envoyer seulement l'identifiant ou une simple chaîne de caractères comme données est de rendre l'URL plus "partageable" et facilement explorable par les robots, etc. Ainsi, le lien résultant peut être partagé par les utilisateurs de votre application. Pour envoyer des objets plus importants, un service sera plus efficace.

5voto

ahankendi Points 210

La troisième approche est le moyen le plus courant de partager des données entre les composants. Vous pouvez injecter le service d'élément que vous voulez utiliser dans le composant lié.

import { Injectable } from '@angular/core';
import { Predicate } from '../interfaces'

import * as _ from 'lodash';

@Injectable()
export class ItemsService {

    constructor() { }

    removeItemFromArray<T>(array: Array<T>, item: any) {
        _.remove(array, function (current) {
            //console.log(current);
            return JSON.stringify(current) === JSON.stringify(item);
        });
    }

    removeItems<T>(array: Array<T>, predicate: Predicate<T>) {
        _.remove(array, predicate);
    }

    setItem<T>(array: Array<T>, predicate: Predicate<T>, item: T) {
        var _oldItem = _.find(array, predicate);
        if(_oldItem){
            var index = _.indexOf(array, _oldItem);
            array.splice(index, 1, item);
        } else {
            array.push(item);
        }
    }

    addItemToStart<T>(array: Array<T>, item: any) {
        array.splice(0, 0, item);
    }

    getPropertyValues<T, R>(array: Array<T>, property : string) : R
    {
        var result = _.map(array, property);
        return <R><any>result;
    }

    getSerialized<T>(arg: any): T {
        return <T>JSON.parse(JSON.stringify(arg));
    }
}

export interface Predicate<T> {
    (item: T): boolean
}

3 votes

Le service est instancié lors du changement de route. Vous perdez donc des données

1 votes

@JimmyKane Vous parlez spécifiquement du moment où la page se rafraîchit, mais si elle ne se rafraîchit pas, la mémoire est toujours sauvegardée dans un service. Cela devrait être le comportement par défaut, car cela permet d'éviter de nombreux chargements.

1 votes

@AaronRabinowitz droit. Désolé pour la confusion. Et désolé pour le vote négatif. J'aimerais pouvoir le défaire maintenant. Trop tard. C'était nouveau pour angular 2 et mon problème en essayant votre approche était que j'avais le service fourni à de nombreux composants et non fourni via le module d'application.

3voto

Passer en utilisant JSON

  <a routerLink = "/link"
   [queryParams] = "{parameterName: objectToPass| json }">
         sample Link                   
  </a>

10 votes

La réponse serait meilleure si vous pouviez montrer comment le paramètre est consommé dans le composant récepteur également - tout le chemin qu'il emprunte. Autrement dit, si quelqu'un ne sait pas comment passer un paramètre, il ne saura pas non plus comment utiliser ce paramètre dans le composant récepteur :)

1 votes

L'inconvénient de cette méthode est que la taille de la chaîne de recherche est limitée et que, parfois, les propriétés des objets ne doivent pas être visibles dans la barre d'adresse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X