angulargoogle-cloud-firestorelazy-loadingangular-resolver

Resolver not returning Firestore's data to load a component in Angular


I'm trying to lazy load a component and I've following this Angular Guide (Angular Guide: Preloading component data), but I'm even don't getting data back from the resolver and so the component isn't being shown. Let's to my flat simple code:

Service

export class OrdersService {
  constructor(private firestore: AngularFirestore, private http: HttpClient) {}

  getCoffeeOrders() {
    // return request = this.http.get('http://date.jsontest.com/'); // Works, but it's not the right data
    return this.firestore.collection<CoffeeOrder>('coffeeOrders').valueChanges();;
  }
}

Resolver

import { Injectable } from '@angular/core';
import {
  Resolve,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
import { CoffeeOrder, OrdersService } from './shared/orders.service';

@Injectable({
  providedIn: 'root',
})
export class GetCoffeeOrdersResolverService implements Resolve<CoffeeOrder[]> {
  constructor(private ordersService: OrdersService) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<CoffeeOrder[]> | any {
    console.log('GetCoffeeOrdersResolver');

    return this.ordersService.getCoffeeOrders();
  }
}

Component

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
  selector: 'app-order-list',
  templateUrl: './order-list.component.html',
  styleUrls: ['./order-list.component.css'],
})
export class OrderListComponent implements OnInit {
  coffeeOrders;
  res;
  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    console.log('ngOnInit');
    this.route.data.subscribe(res => {
      console.log(res);
      this.res = res;
    })
  }
}

Routing

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GetCoffeeOrdersResolverService } from './get-coffee-orders-resolver.service';
import { OrderListComponent } from './order-list/order-list.component';

const routes: Routes = [
  {
    path: '',
    component: OrderListComponent,
    resolve: { orders: GetCoffeeOrdersResolverService },
  },
];

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

My structure version

Angular CLI: 10.1.7
Angular: 10.1.6
Agular Fire: 6.0.3
rxjs: 6.6.3
typescript: 4.0.3

This is my Gist with the files


Solution

  • I tryied somethings after perceive that the request is not endend by the resolver, so the keypoint to solve this is just to complete the request with a workaround pipe in my resolver.

    export class GetPatientsResolverService implements Resolve<Patient[]> {
      constructor(private patientService: PatientService) {}
    
      resolve(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): Observable<Patient[]> {
        return this.patientService
          .getPatients()
          .valueChanges({ idField: 'id' })
          .pipe(take(1)); // HERE IS THE TRICK!
      }
    }
    

    The take(1) method at the pipe call terminate the requisition and after can wait for the answer bringing it to the resolver and service rightly.

    Why use take() instead first()?

    Basically: