Reputation: 99
Been trying to solve this problem for the past few days and i've had no luck.
Here's what i'm trying to do.
My website makes a http get request for a list of projects and using a ngFor loop I display these on the home page. I cache these results using shareReplay on my Observable so that when I view a single item - I won't need to do another network request.
My problem is I can't find a way to extract a single item from the array of observables after it's been cached. I am aware of the .find or .filter but those seem like they are used while getting the observable initially and not after it's been cached with shareReplay.
Below is my code.
//service.ts
get allProjects() {
if (!this.cache$) {
this.cache$ = this.fetchProjects().pipe(shareReplay(1));
}
return this.cache$;
}
fetchProjects() {
return this.http
.get<Project[]>(
'https://admin.steezy.io/wp-json/wp/v2/posts?categories=5'
)
.pipe(
map((projects) => {
return projects.map((item) => {
return new Project(
item.id,
item.slug,
item.title,
item.content,
item.better_featured_image,
new Acf(
item.acf.projectDescription,
item.acf.projectTypeOfWork,
item.acf.sliderLinks
)
);
});
}),
);
}
// component.ts
ngOnInit(): void {
const slug = this.route.snapshot.params['slug'];
this.project = this.projectService.singleProject;
return this.project;
}
I've tried so many combinations. Adding .find in the service won't work because my projects componenet wont get all the projects. I've tired
this.project = this.projectService.cache$.find(
(project) => project.slug == slug
);
But it tells me Property 'find' does not exist on type 'Observable<Project[]>'
I've tried .filter and I get the same issues.
This seems like such an easy thing but for some reason i'm stumped. I already have the data cached, all I need to do is pick one object out based on the slug.
Any ideas?
Edit:
I resolved this issue based on Adrians answer. I have one minor error now that shows up in my IDE
<div class="container" *ngIf="project$ | async as project">
<div class="row my-5">
<div class="col-sm-12 text-center">
<h1>
<!-- {{ project$ | async | json }} -->
{{ project.title.rendered }}
//project.model.ts
export class Project {
constructor(
public id: number,
public slug: string,
public title: Title,
public content: string,
public better_featured_image: string,
public acf: Acf
) {}
}
export class Title {
constructor(public rendered: string) {}
}
export class Acf {
constructor(
public projectDescription: string,
public projectTypeOfWork: string,
public sliderLinks: any = null
) {}
}
The title
is underlined in red and the error my ide gives is Identifier 'title' is not defined. 'null' does not contain such a member
Any idea why?
Upvotes: 0
Views: 367
Reputation: 21638
pipe the observable through a map
this.project$ = this.projectService.cache$.pipe(
map(projects => projects.find(project => project.slug == slug))
);
Note that project$ is an observable, not a project object. You will need to unwrap it with the async pipe or subscribe to it.
Unwrap it like
<ng-container *ngIf="project$ | async as project">
{{ project | json }}
</ng-container>
Upvotes: 1