0

I'm trying to fetch the data from a route and load the data into my state before showing my detail component, and for this reason I have created a resolver. My get request is working, that I know, but it seems as if the api call is done after the component is loaded.

@Injectable()
export class WorkOrderDetailResolver implements Resolve<WorkOrder> {

    constructor(
        private store: Store<fromApp.AppState>
    ) { }

    waitForWorkOrderDataToLoad(route, state) {
        this.store.dispatch(new WorkOrderActions.FetchWorkOrderFromAPIByID(+route.params['id']));
        return this.store.select(state => state.workOrder.workOrderDetails).pipe(take(1));
    }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<WorkOrder> | Promise<WorkOrder> | WorkOrder {
        return this.waitForWorkOrderDataToLoad(route, state);
    }
}

These are my routes where I clearly apply the resolver to the WorkOrderDetailsComponent

   const workOrderRoutes: Routes = [
        { 
            path: 'workorders', 
            component: WorkOrderComponent,
            children: [
                { path: 'new', component: WorkOrderEditComponent },
                { path: 'list', component: WorkOrderListComponent },
                { path: ':id', component: WorkOrderDetailComponent, resolve: { workOrderDetails: WorkOrderDetailResolver } },
                { path: ':id/edit', component: WorkOrderEditComponent }
            ]
         }
    ];

And finally here is the code for the WorkOrdersDetailComponent:

@Component({
  selector: 'app-work-order-detail',
  templateUrl: './work-order-detail.component.html',
  styleUrls: ['./work-order-detail.component.css']
})
export class WorkOrderDetailComponent implements OnInit {
  private id: number; 
  workOrder: WorkOrder;
  workOrderState: Observable<{workOrders: WorkOrder[]}>;

  constructor(private route: ActivatedRoute,
              private router: Router,
            ) { }

  ngOnInit() {
    console.log(this.route.snapshot.data);
    this.workOrder = this.route.snapshot.data.workOrderDetails;
  }

  onEditWorkOrder() {
    this.router.navigate(['edit'], {relativeTo: this.route});
  }

}

To explain what my goal is with the code in the resolver is, Dispatch the action for fetching an workOrder by id from my API and store it the state (this works), once this is done, and ONLY after it is done, return an observable of the workOrder that I stored in the state and load the WorkOrderDetailComponent.

The error I the view cannot read value of null for the workOrder the first time the route is loaded, but what then happens is that if I navigate away and back to the page, the workOrder is not null anymore. So my guess is the resolver is for some reason not doing it's magic before the component is loaded? What I want is for the resolver to return Observable<{WorkOrder]> so that I can load it asynch in the view.

Also, it could very much be just an issue with me not using the rxjs operators properly for this, I'm having quite a hard time grasping how observables work and how these operators should be chained. If that is the case, please enlighten me of what is wrong and why.

Thanks!

emmep
  • 77
  • 10

1 Answers1

2

You should wait until the selector returns a value

this.store.pipe(
  select(state => state.workOrder.workOrderDetails),
  filter(details => !!details),
  take(1)
);

Note that I'm also using the select operator instead of the select method on the store. This is because the select method on the store is deprecated and will be removed in the future.

timdeschryver
  • 9,320
  • 1
  • 12
  • 23
  • Thats amazing, thank you so much for letting me know. So filter basically sits and wait until the result of the select operator is there correct? Also, what does the the "!!" mean? – emmep Aug 17 '18 at 16:10
  • https://stackoverflow.com/questions/784929/what-is-the-not-not-operator-in-javascript , if you don't like the syntax you can also do `Boolean(details)` – timdeschryver Aug 17 '18 at 16:51