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

772 views Asked by At

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

1

There are 1 answers

1
dixavier27 On BEST ANSWER

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:

  • take(n) is not greedy, so will try that it will return the first n elements in the collection and if the collection is empty will not throw an error.
  • first() is greedy, and ensures that it will return exactly one element or throw an error