تایپاسکریپت - انگولار ۲ تلاش برای پیادهسازی Observables در سرویسها
من دارم سعی میکنم دادهها را از یک کامپوننت به کامپوننت دیگر با استفاده از observable ارسال کنم. اینجا من observable را در سرویس اینگونه پیادهسازی میکنم...
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);)
}
و کامپوننت والد من در onselect() دادهها را به یک سرویس مقداردهی اولیه میکند، مانند زیر:
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;
}
}
و کامپوننت فرزند دادهها را از مشترک به این شکل دریافت میکند... اما داده نمایش داده شده نامشخص است و صفحه خالی میبینم.. کجا اشتباه میکنم...
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);
}
}
پاسخ شماره ۱
آنچه شما باید استفاده کنید یک Subject است. اگر تا به حال از EventEmitter در Angular استفاده کردهاید، این نیز یک Subject است. با EventEmitter معمولاً از آن برای انتشار رویدادها از فرزند به والد استفاده میکنیم.
@Component({
template: `
<child (textChange)="onTextChange()"></child>
`
})
class ParentComponent {}
class ChildComponent {
@Output() textChange = new EventEmitter();
onClick() {
textChange.emit('new value');
}
}
اگر تا به حال این را استفاده کردهاید، این همان الگوی انتشار/مشترک شدن است که نیاز دارید. کسی در رویداد مشترک میشود و کسی آن را منتشر میکند. این جایی است که میتوانیم از Subject استفاده کنیم. همانطور که گفتم EventEmitter یک زیرکلاس از Subject است.
برای این مورد، با این حال، Subject ساده ممکن است به اندازه کافی خوب نباشد. دلیلش این است که وقتی رویداد منتشر شد، برای همیشه از بین میرود. اگر کسی مشترک نباشد، هیچ اتفاقی نمیافتد. بنابراین اگر اتفاق بیفتد که شما کمی بعد از انتشار رویداد مشترک شوید، چیزی دریافت نمیکنید. اغلب اوقات، این غیرقابل قبول است.
برای این مورد، میتوانیم از ReplaySubject استفاده کنیم. این نوع سوژه به شما اجازه میدهد یک بافر با اندازه قابل تنظیم داشته باشید. بنابراین اگر درست بعد از انتشار رویداد مشترک شوید، باز هم آن را دریافت خواهید کرد.
در اینجا یک نمونه است
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);
}
}
اکنون مؤلفهای که میخواهد منتشر کند فقط نیاز دارد مورد را تنظیم کند
service.selectedItem = 'new item';
و مؤلفه مشترک
service.selectedItem$.subscribe(item => {})
همچنین ببینید:
- موضوعات RxJS چیستند و مزایای استفاده از آنها چیست؟
- مستندات RxJS درباره Subjects
بهروزرسانی
مشاهده Plunker
پاسخ شماره ۲
شما باید از Observable.create به جای new Observable استفاده کنید
ببینید: مستندات RxJs
