web-dev-qa-db-fra.com

Angular 2 sortie du routeur-prise

Je veux faire la navigation à partir de composants enfants qui rendent à l'intérieur du routeur-prise. Mon composant parent possède une configuration de routeur et je souhaite naviguer manuellement sur certains événements. Mais je ne sais pas comment je peux transmettre d’enfant à parent des données (pour la navigation) sans sortie. Parce que cette construction ne fonctionne pas

 <router-outlet (navigateTo)="navigateToMessagePart($event)"></router-outlet>

Comment je peux le faire de la bonne manière? Peut-être naviguer depuis un enfant? Mais comment puis-je obtenir des méthodes parent de l'enfant. Un grand merci pour toute aide!

47
Velidan

<router-outlet></router-outlet> N'est qu'un espace réservé pour l'ajout de composants routés. Il n'y a pas de support pour tout type de liaison.

Vous pouvez créer un <router-outlet> Personnalisé vous permettant de le faire ou plus commun, utilisez un service partagé pour communiquer entre le composant parent et le composant routé.

Pour plus de détails, voir https://angular.io/docs/ts/latest/cookbook/component-communication.html

mettre à jour

Il y a maintenant un événement qui permet d'obtenir le composant ajouté

<router-outlet (activate)="componentAdded($event)" (deactivate)="componentRemoved($event)"></router-outlet>

qui permet de communiquer (getters d’appel, setters et méthodes) avec le composant dans componentAdded()

Un service partagé est cependant le moyen préféré.

43

<router-outlet></router-outlet> ne peut pas être utilisé pour émettre un événement à partir du composant enfant. Un moyen de communiquer entre deux composants consiste à utiliser un service commun.

Créer un service

service-partagé.ts

import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class SharedService {
    // Observable string sources
    private emitChangeSource = new Subject<any>();
    // Observable string streams
    changeEmitted$ = this.emitChangeSource.asObservable();
    // Service message commands
    emitChange(change: any) {
        this.emitChangeSource.next(change);
    }
}

Maintenant, injectez l'instance du service ci-dessus dans le constructeur des composants parent et enfant.

Le composant enfant émettra un changement chaque fois que la méthode onClick () sera appelée

child.component.ts

import { Component} from '@angular/core';
@Component({
    templateUrl: 'child.html',
    styleUrls: ['child.scss']
})
export class ChildComponent {
    constructor(
        private _sharedService: SharedService
    ) { }

onClick(){
  this._sharedService.emitChange('Data from child');

 }
}

Le composant parent doit recevoir ce changement. Pour ce faire, capturez l'abonnement dans le constructeur du parent.

parent.component.ts

import { Component} from '@angular/core';
@Component({
    templateUrl: 'parent.html',
    styleUrls: ['parent.scss']
})
export class ParentComponent {
    constructor(
        private _sharedService: SharedService
    ) {
          _sharedService.changeEmitted$.subscribe(
        text => {
            console.log(text);
        });
      }

}

J'espère que cela t'aides :)

111
Antara Datta

La réponse donnée ci-dessus est correcte et complète. Je veux simplement ajouter à ceux pour qui la solution ne fonctionnait pas qu'ils devraient ajouter le service aux fournisseurs uniquement dans le composant parent et non à l'enfant pour garantir que vous obteniez un singleton du service, sinon deux instances de service seront établi. Cette réponse est inspirée par le commentaire de @HeisenBerg dans la réponse précédente.

5
Bacem

J'ai un peu changé avec la réponse d'Antara Datta. J'ai créé un service d'abonné

import {Injectable} from '@angular/core';
import {Subject} from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class Subscriber<T>
{
  protected observable = new Subject<T>();

  public next(item: T)
  {
    this.observable.next(item);
  }

  public subscribe(callback: (item:T)=>void) {
    this.observable.subscribe(callback);
  }
}

Chaque fois que j'ai besoin de deux composants pour partager des informations, j'injecte ce service dans le constructeur qui y est abonné:

 constructor(protected layoutOptions: Subscriber<Partial<LayoutOptions>>)
 {
    layoutOptions.subscribe(options => this.options = Object.assign({}, this.options, options));
 }

et celui qui le met à jour

constructor(protected router: Router, protected apiService: ApiService, protected layoutOptions: Subscriber<Partial<LayoutOptions>>)
  {
    this.layoutOptions.next({showNavBar: false});
  }
2
Raza