user2444539
user2444539

Reputation: 99

How do I find a single item from a cached observable array

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

Answers (1)

Adrian Brand
Adrian Brand

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

Related Questions