2017-02-16 3 views
2

Ich versuche, Daten zwischen zwei Komponenten über einen Dienst zu senden. Ich habe jedoch Probleme mit dem Datenauffüllen, wenn die "untergeordnete" Komponente zuerst geladen wird.Senden von Daten zwischen Komponenten mit einem Dienst in Angular 2

Wenn Sie ein 'release' aus der ungeordneten Liste in der release-list.component auswählen, wird die release-detail.component über einen Router-outlet geladen. Die Release-Detail-Komponente sollte den Veröffentlichungskünstler anzeigen.

Es funktioniert, wenn Sie ein Release auswählen und dann ein Release ein zweites Mal auswählen. Aber ich muss die release-detail.component zweimal laden, bevor die Daten gefüllt sind. Ich fühle mich nahe, aber ich muss etwas verpassen. Jede Hilfe würde sehr geschätzt werden.

Dank

Ich habe beide bezogen auf eine previous question und die Angular documentation

release.service.ts

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

import { MockReleaseList, ReleaseInterface } from './mock-releases'; 

@Injectable() 

export class ReleaseService { 
    private releaseSubject$ = new Subject(); 

    getReleases(): ReleaseInterface[] { 
     return MockReleaseList; 
    } 

    getRelease() { 
     return this.releaseSubject$; 
    } 

    updateRelease(release: {artist: string, title: string, category: string}[]) { 
     // console.log(release); 
     this.releaseSubject$.next(release); 
    } 

} 

Release-list.component.ts

import { Component, OnInit } from '@angular/core'; 

import { Router } from '@angular/router'; 
import { Location } from '@angular/common'; 

import { ReleaseService } from '../../../shared/services/release.service'; 
import { MockReleaseList, ReleaseInterface } from '../../../shared/services/mock-releases'; 

@Component({ 
    selector: 'ostgut-releases', 
    template: ` 
    <h3>Label List</h3> 
    <ul> 
     <li *ngFor="let release of releases" (click)="onSelect(release)">{{ release.artist }}</li> 
    </ul> 
    <router-outlet></router-outlet> 
    `, 
}) 
export class ReleaseListComponent implements OnInit { 
    private releases: ReleaseInterface[]; 

    constructor (
     private _router: Router, 
     private _releaseService: ReleaseService 
    ) {} 

    ngOnInit(): ReleaseInterface[] { 
     return this.releases = this._releaseService.getReleases(); 
    } 

    onSelect(release: any): void { 
     this._releaseService.updateRelease(release); 
     this._router.navigate(['/release-list/release-detail', release.category]); 
    } 

} 

release-detail.component.ts

import { Component, OnInit, Input } from '@angular/core'; 

import { Router, ActivatedRoute, Params } from '@angular/router'; 

import { ReleaseService } from '../../../../shared/services/release.service'; 
import { ReleaseInterface } from '../../../../shared/services/mock-releases'; 

@Component({ 
    selector: 'ostgut-release-detail', 
    template: ` 
    <h3>Release Detail</h3> 
    <p>{{ release.artist }}</p> 
    `, 
}) 
export class ReleaseDetailComponent implements OnInit { 
    private routeParam: string; 
    private routeParamSub: any; 
    private release: any; 

    constructor(
     private _activatedRoute: ActivatedRoute, 
     private _router: Router, 
     private _releaseService: ReleaseService 
    ) {} 

    ngOnInit(): void { 
     this.release = this._releaseService.getRelease().subscribe(release=>{ 
      return this.release = release; 
     }); 
    } 

} 

Antwort

2

ich glaube, das Problem könnte sein, dass Ihre Subject seinen Wert veröffentlicht, bevor Sie in Ihrem ReleaseDetailComponent es abonniert haben. Wenn Sie es das zweite Mal tun, wird eine neue Release veröffentlicht, und die ReleaseDetailComponent ist bereits erstellt - was bedeutet, dass es funktioniert.

Um dies zu beheben, können Sie versuchen, eine BehaviorSubject anstelle einer regulären Subject in Ihrem Dienst zu verwenden. Die BehaviorSubject gibt Ihnen den neuesten veröffentlichten Wert, auch wenn Sie es abonnieren, nachdem der letzte Wert veröffentlicht wurde. Es erwartet jedoch auch einen Standardwert, daher sollten Sie in Ihrer Vorlage ReleaseDetailComponent einige Null-Überprüfung hinzufügen.

Eine Implementierung könnte wie folgt aussehen:

import { Injectable } from '@angular/core'; 
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; // <-- note the import! 

import { MockReleaseList, ReleaseInterface } from './mock-releases'; 

@Injectable() 

export class ReleaseService { 
    private releaseSubject$ = new BehaviorSubject(undefined); 

    // The rest is the same 

} 

Und in Ihrer Vorlage, att null Prüfung, als Standardwert wir die BehaviorSubject gesetzt ist undefined. Natürlich können Sie den Standardwert (die Werte, die in den Konstruktor der BehaviorSubject übergeben werden) auf eine leere Release oder etwas anderes setzen, wenn Sie möchten.

template: ` 
    <h3>Release Detail</h3> 
    <p>{{ release?.artist }}</p> <!-- Note the '?' --> 
    `, 

Hier sind die Dokumente, wenn Sie mehr über die verschiedenen Arten von Subjects lernen:

Ich hoffe, das hilft!

+0

Brilliant. Danke, Fredrik! Die RxJS-Konzepte sind für mich noch neu und ich hatte das Gefühl, dass ich dort ein bisschen abseits der Strecke wäre. Die einzige andere Sache, die ich ändern musste, war der ReleaseDetailComponent und ngOnInit Hook -> this.release = this._releaseService.getRelease(). Subscribe (release => { return this.release = release; }); – bmd

+0

Fertig! Und danke nochmal – bmd

+0

Gerne helfen! :) –

2

Verwenden Sie BehaviorSubject als Delegat.BehaviorSubject auf ein Abonnement gibt den letzten Wert des Subjekts, also die Komponente postponely immer mit dem letzten Wert geladen werden aktualisiert:

@Injectable 
export class ReleaseService { 
    releaseSource: BehaviorSubject = new BehaviorSubject(null); 

    // No difference when it comes to subscribing to the BehaviorSubject 
} 

Grund Beispiel BehaviorSubject in Aktion: Angular 2 Interaction between components using the service

+0

Danke, Seidme. Sowohl du als auch Fredrik waren auf dem Punkt. Sehr geschätzt! – bmd

+0

Gern geschehen, froh, dass es geholfen hat ^^. –

+0

Fertig. Danke, Seidme – bmd

0

Ich glaube, Sie mischen zwei Konzepte hier. Es gibt zwei Möglichkeiten, es zu tun:

  1. In der Release-Detail-Komponente Sie die release mit @Input erklären und Sie geben es aus der Auflösung-Liste. Das wird Ihnen als Variable in der Komponente zur Verfügung stehen. Kein Thema, kein Abo.
  2. Sie verwenden einen Dienst wie oben, aber Sie laden bereits die Details. Wie es in der Freigabeliste html eingebettet, aber mit *ngIf auf false gesetzt, nicht angezeigt. Wenn Sie das ausgewählte Release in Ihr Thema einfügen und es startet, können Sie *ngIf auf true setzen und den Release-Detail-Part anzeigen.
Verwandte Themen