Angular 4 How to return multiple observables in resolver

元气小坏坏 提交于 2019-12-01 17:34:22

问题


Basically as a title states, I need to return multiple observables or maybe a results. The goal is basically to load lets say a library list and then load a books based on that library ID's. I don't want to call a service in components, instead I want all the data to be loaded before the page load.

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { UserService } from './../_services/index';

    @Injectable()
    export class LibraryResolver implements Resolve<any> {

        constructor(private _userService: UserService) {}

        resolve(route: ActivatedRouteSnapshot) {
            return this._userService.getLibraryList();
        }
    }

How can I load library list first and then load books info for each library and return to my component?

PS: My service got this method to load by Id

this.userService.getLibraryBooks(this.library["id"]).subscribe((response) => {
...

回答1:


I found a solution for this issue, maybe will help somebody, so basically I've used forkJoin to combine multiple Observables and resolve all of them.

resolve(route: ActivatedRouteSnapshot): Observable<any> {
        return forkJoin([
                this._elementsService.getElementTypes(),
                this._elementsService.getDepartments()
                .catch(error => {

                    /* if(error.status === 404) {
                        this.router.navigate(['subscription-create']);
                    } */

                    return Observable.throw(error);
                })
        ]).map(result => {
            return {
                types: result[0],
                departments: result[1]
            };
        });
    };

Now it works correctly, as intended.




回答2:


You can easily resolve multiple observables using withLatestFrom.

Here's a working demo in Stackblitz: https://stackblitz.com/edit/angular-xfd5xx

Solution below.

In your resolver, use withLatestFrom to combine your observables:

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Library } from '../models/library.model';
import { LibraryBook } from '../models/library-book.model';
import { LibraryService } from '../services/library.service';
import { Observable } from 'rxjs';
import { withLatestFrom } from 'rxjs/operators';

@Injectable()
export class LibraryDisplayResolver implements Resolve<[Library, LibraryBook[]]> {

  constructor(
    private _libraryService: LibraryService,
  ) { }

  resolve (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<[Library, LibraryBook[]]> {
    const libraryId = route.params['id'];
    return this._libraryService.getLibrary(libraryId).pipe(
      withLatestFrom(
        this._libraryService.getBooksFromLibrary(libraryId)
      )
    );
  }
}

Make sure your resolver is set in your route with an appropriate identifier:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LibraryDisplayComponent } from './library-display.component';
import { LibraryDisplayResolver } from '../resolvers/library-display.resolver';

const routes: Routes = [
  {
    path: ':id',
    component: LibraryDisplayComponent,
    resolve: {
      libraryResolverData: LibraryDisplayResolver
    }
  },
  {
    path: '',
    redirectTo: '1',
    pathMatch: 'full'
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class LibraryDisplayRoutingModule { }

In the receiving component, you can access snapshots of both observables like so:

import { Component, OnInit } from '@angular/core';
import { LibraryBook } from '../models/library-book.model';
import { Library } from '../models/library.model';
import { ActivatedRoute } from '@angular/router';

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'library-display',
  templateUrl: './library-display.component.html',
  styleUrls: ['./library-display.component.scss']
})
export class LibraryDisplayComponent implements OnInit {

  library: Library;
  libraryBooks: LibraryBook[];

  constructor(
    private route: ActivatedRoute
  ) { }

  ngOnInit() {
    this.library = this.route.snapshot.data['libraryResolverData'][0];
    this.libraryBooks = this.route.snapshot.data['libraryResolverData'][1];
  }
}



回答3:


I have a similar situation, but I approached it slightly differently.

In your case, my understanding is you want to get the query parameter, and then based on the response, call a few more services.

The way I do that is by having a component that wraps around the others, and passes the objects they need. I subscribe to them through the route paramMap and then wrap all my other calls in a. Observalbe.forkJoin

In my wrapper component I do the following:

ngOnInit() {

    this.route.params.subscribe((params) => {
        if (params.hasOwnProperty('id') && params['id'] != '') {
            const slug = params['slug'];
            Observable.forkJoin([
                this.myService.getData(id),
                this.myService.getOtherData(id),
            ]).subscribe(
                ([data, otherData]) => {
                    this.data = data;
                    this.otherData = otherData;
                },
                error => {
                    console.log('An error occurred:', error);
                },
                () => {
                    this.loading = false;
                }
                );
        }
    });

Not entirely what you're after but I hope it points you in the right direction




回答4:


I would suggest you use Observables, they will make your life a lot easy. Check these two articles for more details on how to achieve that using observables:

http://www.syntaxsuccess.com/viewarticle/combining-multiple-rxjs-streams-in-angular-2.0

http://blog.danieleghidoli.it/2016/10/22/http-rxjs-observables-angular/

I personally use flatMap

Good Luck.



来源:https://stackoverflow.com/questions/48146996/angular-4-how-to-return-multiple-observables-in-resolver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!