简体   繁体   中英

How to “chain” two seperate observables in Angular 2

I am developing a web application with Angular2 and I have got some problems with getting data from the server.

 import ...

 @Component({
 ...

 })
 export class EmployeeManagementTableComponent implements OnInit, OnDestroy{

private employees: Employee[];
private departments: SelectItem[] = [];
private selectedDepartment: string;
private columns: any[];
private paramSub: any;
private employeesSub: any;
private departmentSub: any;


constructor(private employeeManagementService: EmployeeManagementService, 
            private route: ActivatedRoute, 
            private router: Router,
            private ccs: ComponentCommunicatorService,
            private logger: Logger) { }

ngOnInit(){

    this.columns = [
     ...
    ];

    //ccs is just a service for storing/getting app wide infomation

    this.selectedDepartment = this.ccs.getSelectedDepartment();
    this.getDepartments();
    this.getEmployees(this.selectedDepartment);

    ...
}

ngOnDestroy(){
    /*this.employeesSub.unsubscribe();
    this.departmentDub.unsubscribe();*/
}

getDepartments(){

    this.departments.push({label: 'Alle', value: 'all'});

    this.departmentSub = this.employeeManagementService.getDepartments().subscribe(
          data =>  {data.forEach((item, index) => {
                        this.departments.push({label: item, value: index.toString()});
                    });    
                   },
          err => this.logger.error(err),
          () => {this.logger.log('done loading');
                 this.departmentSub.unsubscribe()}
    );
}
getEmployees(department: any){

this.employeesSub = this.employeeManagementService.getEmployees(department).subscribe(
          data => {this.employees = data},
          err => this.logger.error(err),
          () => {this.logger.log('done loading');
                 this.employeesSub.unsubscribe()}
    );
}

As you see when the component gets initalized it calls two Methods for getting data. The methods get observables from my service and subscribe to them.
The problem is that order is like call1, call2, result1, result2, ... and I think there is something not right. It should be call1, result1, call2, result2, ... or am I wrong? I tried subscribing to observable2 in the onComplete of observable1 but I think dedicated methods would be useless then. I have researched and found some solutions with subscribing to both observables simultaneously with concat but I just want the code to continue after getDepartments() when all data traffic is finished.

And should I unsubscribe in the OnDestroy() or in the OnComplete of the subscribe function I don't really get the difference?

If you want to control the execution order of observables, you need to build an asynchronous data flow leveraging operators like flatMap (execution in series) or Observable.forkJoin (execution in parallel)

Here are samples:

// Series
someObservable.flatMap(result1 => {
  return someOtherObservable;
}).subscribe(result2 => {
  (...)
  (...)
});

// Parallel
Observable.forkJoin([ someObservable, someOtherObservable ])
  .subscribe(results => {
    let result1 = results[0];
    let result2 = results[1];
  });

Usually, such calls are asynchronous, and in consequence, the order of execution and/or arriving results is not deterministic. (Example: When requesting data from API 1 and then from API 2, it might even result in data from API 2 arriving before data from API 1 if API 1 is especially slow or the amount of data is huge.) So, to answer your first question: yes, you are wrong.

When subscribing to the Observable, you probably have some kind of callback function (the place where the data received is used or stored) which is executed by the 1st service once the data arrives. If it is important to trigger the 2nd API call only after receiving the result for the 1st call, this function would be the place to request data from the 2nd service. Of course, you will not want to couple service 1 and service 2, so a better approach would be to pass a callback function to service 1 which is to be invoked in case of success. Then, your client code can make sure that this callback function requests data from the 2nd service. Of course, there are numerous ways how to handle such cases, and what I described before is just a simple approach.

Regarding the unsubscribing issue: often, it is not desired to unsubscribe when receiving results, as there might be more data coming in afterwards. (This is one of the key differences between Promises and Obvservables). For instance, in an application I am working on, I unsubscribe when “leaving” the component, as I do want to keep on subscribing after I received initial data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM