I'm trying to implement the filter operator from rxjs, to filter out different portflios ALL | APP | WEB |API

I expect the filter to filter out the portfolios according to the property type:

Here is the filter implemmentation
Why does the click not filter portfolios here? what concept I'm I missing?
portfolios: IPortfolio[] = [];
portfolioType: 'all' | 'app' | 'web'|'api' = 'all';
errorMessage = '';
sub!: Subscription;
ngOnInit(): void {
this.sub = this.portFolioService.getPortfolioData().subscribe({
next: portfolios => {
this.portfolios = portfolios;
filter((portfolio: IPortfolio) => portfolio.type === this.portfolioType);
},
error: err => this.errorMessage = err
})
}
and the view html has
<ul id="portfolio-filters">
<li [class.filter-active]="portfolioType == 'all'" (click)="portfolioType = 'all'">All</li>
<li [class.filter-active]="portfolioType == 'app'" (click)="portfolioType = 'app'">APP</li>
<li [class.filter-active]="portfolioType == 'web'" (click)="portfolioType = 'web'">WEB</li>
<li [class.filter-active]="portfolioType == 'api'" (click)="portfolioType = 'api'">API</li>
</ul>
You need to use a .pipe() where you can put a map to transform the portfolios with filter. Placing it as an expression inside the next callback will have no effect.
this.portfolioService.getPortfolioData().pipe(
map(portfolios => portfolios.filter(portfolio => this.portfolioType === portfolio.type))
).subscribe(portfolios => {
// portfolios are filtered now
})
As your instance type IPortfolio[] is an array, you should use Array.prototype.filter to filter your portfolios:
portfolios: IPortfolio[] = [];
portfolioType: 'all' | 'app' | 'web'|'api' = 'all';
errorMessage = '';
sub!: Subscription;
ngOnInit(): void {
this.sub = this.portFolioService.getPortfolioData().subscribe({
next: portfolios => {
this.portfolios = portfolios.filter(portfolio => portfolio.type === this.portfolioType)
},
error: err => this.errorMessage = err
})
}
After carefully reading rxjs Documentation, I got the method to best work:
import { Component, OnInit, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { IPortfolio } from '../portfolio';
import { PortfolioService } from '../portfolio.service';
@Component({
selector: 'app-section-portfolio',
templateUrl: './section-portfolio.component.html',
styleUrls: ['./section-portfolio.component.scss']
})
export class SectionPortfolioComponent implements OnInit {
private unsubscribe$: Subject<boolean> = new Subject<boolean>();
constructor(
private portfolioService: PortfolioService
) { }
private portfolios: IPortfolio[] = [];
public portfolios$: BehaviorSubject<Array<IPortfolio>> = new BehaviorSubject<Array<IPortfolio>>([]);
portfolioType: string = 'all';
ngOnInit() {
this.getAllPortfolios();
}
private getAllPortfolios () {
this.portfolioService.getPortfolioData().pipe(
takeUntil(this.unsubscribe$)
).subscribe((portfolios: Array<IPortfolio>) => {
this.portfolios = portfolios;
this.portfolios$.next(this.portfolios);
})
}
public applyFilter (filter: string) {
this.portfolioType = filter
if (filter === 'all') {
this.portfolios$.next(this.portfolios);
return;
}
const filteredPortfolios = this.portfolios.filter(portfolio => portfolio.type === filter);
this.portfolios$.next(filteredPortfolios);
console.log(this.portfolioType)
}
}
and in the template
<ul id="portfolio-filters">
<li [ngClass]="portfolioType === 'all'? 'filter-active':''"(click)="applyFilter ('all')">All</li>
<li [ngClass]="portfolioType === 'app'? 'filter-active':''" (click)="applyFilter ('app')">APP</li>
<li [ngClass]="portfolioType === 'web'? 'filter-active':''" (click)="applyFilter ('web')">WEB</li>
<li [ngClass]="portfolioType === 'api'? 'filter-active':''" (click)="applyFilter ('api')">API</li>
</ul>
</div>
</div>
<div *ngFor="let portfolio of (portfolios$|async)">
<!-- End Portfolio Section -->