CẬP NHẬT: 9/24/16 Angular 2.0 Ổn định
Câu hỏi này nhận được rất nhiều lưu lượng truy cập, vì vậy, tôi muốn cập nhật nó. Với sự điên rồ của những thay đổi từ các ứng cử viên Alpha, Beta và 7 RC, tôi đã ngừng cập nhật các câu trả lời SO của mình cho đến khi chúng ổn định.
Đây là trường hợp hoàn hảo để sử dụng Chủ đề và ReplaySubjects
Cá nhân tôi thích sử dụng ReplaySubject(1)
vì nó cho phép giá trị được lưu trữ cuối cùng được thông qua khi người đăng ký mới đính kèm ngay cả khi trễ:
let project = new ReplaySubject(1);
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject
project.next(result));
//add delayed subscription AFTER loaded
setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});
//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234
Vì vậy, ngay cả khi tôi đính kèm muộn hoặc cần tải sau, tôi luôn có thể nhận được cuộc gọi mới nhất và không lo bị lỡ cuộc gọi lại.
Điều này cũng cho phép bạn sử dụng cùng một luồng để đẩy xuống:
project.next(5678);
//output
//Subscription Streaming: 5678
Nhưng nếu bạn chắc chắn 100%, rằng bạn chỉ cần thực hiện cuộc gọi một lần thì sao? Rời khỏi các đối tượng mở và quan sát không tốt nhưng luôn có câu "Điều gì sẽ xảy ra?"
Đó là nơi AsyncSubject xuất hiện.
let project = new AsyncSubject();
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
err => console.log(err),
() => console.log('Completed'));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject and complete
project.next(result));
project.complete();
//add a subscription even though completed
setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});
//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234
Tuyệt vời! Mặc dù chúng tôi đã đóng chủ đề, nó vẫn trả lời với điều cuối cùng nó tải.
Một điều nữa là cách chúng tôi đăng ký cuộc gọi http đó và xử lý phản hồi. Bản đồ là tuyệt vời để xử lý các phản ứng.
public call = http.get(whatever).map(res => res.json())
Nhưng nếu chúng ta cần lồng những cuộc gọi đó thì sao? Có, bạn có thể sử dụng các đối tượng có chức năng đặc biệt:
getThing() {
resultSubject = new ReplaySubject(1);
http.get('path').subscribe(result1 => {
http.get('other/path/' + result1).get.subscribe(response2 => {
http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
})
})
return resultSubject;
}
var myThing = getThing();
Nhưng đó là rất nhiều và có nghĩa là bạn cần một chức năng để làm điều đó. Nhập Bản đồ phẳng :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Thật ngọt ngào, var
có thể quan sát được dữ liệu từ cuộc gọi http cuối cùng.
OK đó là tuyệt vời nhưng tôi muốn một dịch vụ angular2!
Tôi có bạn:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';
@Injectable()
export class ProjectService {
public activeProject:ReplaySubject<any> = new ReplaySubject(1);
constructor(private http: Http) {}
//load the project
public load(projectId) {
console.log('Loading Project:' + projectId, Date.now());
this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
return this.activeProject;
}
}
//component
@Component({
selector: 'nav',
template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
export class navComponent implements OnInit {
public project:any;
constructor(private projectService:ProjectService) {}
ngOnInit() {
this.projectService.activeProject.subscribe(active => this.project = active);
}
public load(projectId:string) {
this.projectService.load(projectId);
}
}
Tôi là một fan hâm mộ lớn của các nhà quan sát và quan sát nên tôi hy vọng bản cập nhật này có ích!
Câu trả lời gốc
Tôi nghĩ rằng đây là một trường hợp sử dụng của việc sử dụng một đề Quan sát hoặc trong Angular2
các EventEmitter
.
Trong dịch vụ của bạn, bạn tạo một EventEmitter
cái cho phép bạn đẩy các giá trị lên nó. Trong Alpha 45 bạn phải chuyển đổi nó với toRx()
, nhưng tôi biết họ đã làm việc để loại bỏ điều đó, vì vậy trong Alpha 46 bạn có thể chỉ cần trả lại EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
Cách này có một EventEmitter
chức năng mà các chức năng dịch vụ khác nhau của bạn bây giờ có thể đẩy lên.
Nếu bạn muốn trả lại một quan sát trực tiếp từ một cuộc gọi, bạn có thể làm một cái gì đó như thế này:
myHttpCall(path) {
return Observable.create(observer => {
http.get(path).map(res => res.json()).subscribe((result) => {
//do something with result.
var newResultArray = mySpecialArrayFunction(result);
observer.next(newResultArray);
//call complete if you want to close this stream (like a promise)
observer.complete();
});
});
}
Điều đó sẽ cho phép bạn làm điều này trong thành phần:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
Và lộn xộn với kết quả từ cuộc gọi trong dịch vụ của bạn.
Tôi thích tự tạo EventEmitter
luồng trong trường hợp tôi cần truy cập vào luồng từ các thành phần khác, nhưng tôi có thể thấy cả hai cách hoạt động ...
Đây là một plunker hiển thị một dịch vụ cơ bản với trình phát sự kiện: Plunkr