typescript - Angular 2 försöker implementera Observables i tjänster
Jag försöker skicka data från en komponent till en annan med hjälp av observable. Här implementerar jag observable i tjänsten på detta sätt...
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/RX'
@Injectable()
export class SelectedItemService {
stream1$:Observable<any>;
selectedItem:JSON;
stream1$= new Observable(observer=> setTimeout(() => {
observer.next(this.selectedItem);
}, 3000);)
}
och min överordnade komponent initierar data till en tjänst i onselect() som nedan:
import { Component } from '@angular/core';
import {Http, Headers,Response } from '@angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import {SelectedItemService} from './selecteditem.service'
@Component({
selector: 'newcomponent',
template:`<p>
</p>
<h2>Your Title: {{nameValue}}</h2>
<ul><li *ngFor="let list of lists">Hello {{ list }}</li></ul>
<form class="ui large form segment">
<h3>Add a Link</h3> <div>
<label for="title">Title:</label>
<input [(ngModel)]="nameValue" placeholder="title" name="Title" >
</div>
<label for="link">Link:</label> <input name="link"></form>
<div class=container *ngFor="let data of dataServer"
[class.selected]="data === selectedItem"
(click)="onSelect(data)">
<div id="myimages">
<a routerLink="/SecondNewCom">
<img src="myBaseurl/{{data.images.image3}}">
</a>
<router-outlet></router-outlet>
</div>
<div class=caption> {{data.productName}} </div>
</div>`,
styleUrls: [`./app/mydoc.css`]
})
export class NewComponent {
nameValue: string;
lists: string[];
url:string;
dataServer:JSON[];
length:number;
selectedItem:JSON;
constructor(private http:Http, public myservice:SelectedItemService) {
this.myservice=myservice;
this.nameValue = "declaredName";
this.url="myBaseurl";
this.lists = ['abc', 'xyz', 'lol'];
this.http.get(this.url).map((res:Response) => res.json())
.subscribe(
data => { this.dataServer = data
this.length=Object.keys(this.dataServer).length},
err => console.error(err),
() => console.log('done')
);}
onSelect(data:JSON):void{
this.selectedItem=data;
this.myservice.selectedItem=data;
}
}
och barnkomponenten tar emot data från prenumeranten så här... men de visade uppgifterna är undefined och jag ser en tom skärm.. Var gör jag fel...
import {Component,Input} from '@angular/core';
import {SelectedItemService} from './selecteditem.service'
@Component({
selector:'secondcomponent',
template:`<h1> This is second new Component</h1>
<h1>{{UiSelectedItem}}</h1>
`
})
export class SecondComponent{
UiSelectedItem:JSON;
constructor(public mservice:SelectedItemService) {
this.mservice=mservice;
mservice.stream1$.subscribe(value=>this.UiSelectedItem=value);
}
}
Svar #1
Vad du borde använda är en Subject. Om du någonsin har använt Angulars EventEmitter, är detta också en Subject. Med EventEmitter brukar vi vanligtvis använda det för att publicera händelser från barn till förälder
@Component({
template: `
<child (textChange)="onTextChange()"></child>
`
})
class ParentComponent {}
class ChildComponent {
@Output() textChange = new EventEmitter();
onClick() {
textChange.emit('new value');
}
}
Om du någonsin har använt detta tidigare, är detta publicera/prenumerera-mönstret som du behöver. Någon prenumererar på händelsen, och någon publicerar den. Här kan vi använda Subject. Som jag sa är EventEmitter en underklass av Subject.
För detta fall kanske dock den vanliga Subject inte är tillräcklig. Anledningen är att när händelsen väl sänds ut, försvinner den för alltid. Om ingen har prenumererat händer ingenting med den. Så om det råkar vara så att du prenumererar precis en liten stund efter att händelsen sändes ut, får du ingenting. Ofta är detta oacceptabelt.
För detta fall kan vi använda en ReplaySubject. Denna typ av subject gör att du kan behålla en buffert med konfigurerbar storlek. Så om du prenumererar precis efter att händelsen sändes kommer du ändå att få den.
Här är ett exempel
import { ReplaySubject } from 'rxjs/ReplaySubject';
export class SelectedItemService {
private _selectedItem = new ReplaySubject<string>(1); // buffer size 1
selectedItem$ = this._selectedItem.asObservable();
set selectedItem(item: string) {
this._selectedItem.next(item);
}
}
Nu behöver bara komponenten som vill publicera sätta objektet
service.selectedItem = 'new item';
Och den prenumererande komponenten
service.selectedItem$.subscribe(item => {})
Se även:
- Vad är RxJS Subject och fördelarna med att använda dem?
- RxJS-dokumentation om Subjects
UPPDATERA
Se Plunker
Svar #2
Du bör använda Observable.create istället för new Observable
Se: RxJs-dokumentation
