I am trying to use a resolver to attach data to my route when routing to specific items within a collection. I had my data stored locally in a service and used a method on the service to find the item whose name matched the route param I was searching. This worked perfectly, but then I changed it to try use a call to the database for information instead. Now I am unable to figure out how to sort through the returned data for the specific item I want in the resolver service.
Here is my resolver service:
@Injectable()
export class FoodResolver implements Resolve<any> {
constructor(private foodService: FoodService) {}
resolve(route: ActivatedRouteSnapshot) {
this.foodService.getFood().subscribe((data) => {
return data.find((food) => {
return food.name == route.params["name"];
})
})
}
}
getFood makes a simple call: return this.http.get<Array<FoodModel>>("/api/foods")
and I am using InMemoryWebApi to mock the database.
In my component I get the data in ngOnInit:
ngOnInit(): void {
this.food = this.route.snapshot.data["food"];
}
If someone could point me to where I'm going wrong it would be much appreciated. I added console logs throughout. The order:
ngOnInit: food = undefined.
Html render error: Cannot read property name of undefined.
Food Resolver: Logs correct food list and correct item I want to find.
Html render error: Cannot read property name of undefined.
When I just return the getFood method without altering it so that it displays the entire collection of foods it works perfectly. Because of this and the delay on the foodResolver logs i assumed the resolver needs to return an observable. So I wrapped the function in a new observable:
resolve(route: ActivatedRouteSnapshot) {
const observable = new Observable((observer) => {
observer.next(
this.foodService.getFood().subscribe((data) => {
return data.find((food) => {
return food.name == route.params["name"];
})
})
);
observer.complete();
})
return observable;
}
In doing this all the errors are gone, but no information displays. In ngOninit food is a subscriber. And now I'm out of ideas. If someone could assist me it would be very much appreciated. Thank you.
Sidenote: I would prefer not to filter the list inside the component itself for reusability sake if possible. Also I do not have my data set out with id's so cannot call http.get("/food/lasagna") for example
Signature of resolve
suggests returning an Observable<T>
/Promise<T>
. You're not returning anything.
Try this:
import { map } from 'rxjs/operators';
...
@Injectable()
export class FoodResolver implements Resolve < any > {
constructor(private foodService: FoodService) {}
resolve(route: ActivatedRouteSnapshot) {
return this.foodService.getFood().pipe(
map(
data => data.find(food => food.name == route.params["name"])
)
)
}
}