Home > Enterprise >  Angular: Trying to turn my function into rxjs
Angular: Trying to turn my function into rxjs

Time:05-31

I have a function that is implemented and works properly I want to make it rxjs with filter in rxjs directory use both pipe and includes

And update with subscribe

  posts: Post[] = [];
   validPosts: Post[] = [];
   authorName: string = "";

this is my function:

SearchPostsByName($event: Event) {
    const searchKey = ($event.target as HTMLInputElement).value;

    if (searchKey === '') {
      this.validPosts = this.posts;
      return;
    }
    
    this.validPosts = this.posts.filter(
      value => value.authorName.includes(this.searchName)
    );
  }

CodePudding user response:

To build a search using an input field, you bind the input element to a @ViewChild.

<label>Search Posts </label>
<div>
  <input #search type="text" [value]="filterInput" />
</div>
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {

  @ViewChild('search', { static: true }) search: ElementRef;

  private subscription: Subscription;

  public posts$: Observable<Post[]>;
  public filterInput: string = '';
  public errorMessage: string = '';

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

  ...

}

In the AfterViewInit, you add an observable to the keyup event of the element. Through a pipe, you map the event to its value. You add a debounceTime so the observable doesn't emit too often, and you only listen to changes trough distinctUntilChanged.

Within the subscription itself, you check the input value and change the url queryParams based upon the input.

ngAfterViewInit() {
  this.subscription = fromEvent(this.search.nativeElement, 'keyup')
    .pipe(
      map((event: KeyboardEvent) => (event.target as HTMLInputElement).value),
      debounceTime(500),
      distinctUntilChanged()
    )
    .subscribe((filter) => {
      const queryParams = filter ? { queryParams: { filter } } : undefined;
      this.router.navigate(['.'], {
        relativeTo: this.route,
        ...queryParams,
      });
    });
}

During OnInit, you switchMap the observable of the route's queryParams to a new observable which will fetch the filtered posts from your database through the service. Upon a window refresh the filter query from the url will also be set as the input value.

private fetchPosts() {
  this.posts$ = this.route.queryParams
    .pipe(
      switchMap((params) => {
        if (params.filter) this.filterInput = params.filter;
        return this.appService.fetchPosts(params.filter);
      })
    )
    .pipe(
      catchError((err) => {
        this.errorMessage = err;
        return EMPTY;
      })
    );
}

ngOnInit() {
  this.fetchPosts();
}

In order to show the content, you subscribe to the observable through an async pipe within the html.

<div *ngIf="posts$ | async as posts; else loadingOrError">
  <div *ngIf="!posts.length">
    <h3>No posts found</h3>
  </div>
  <div *ngFor="let post of posts">
    <b>{{ post?.content }}</b>
    <br/>
    <i>
      by <b>{{ post?.authorName }}</b> at
      <b>{{ post?.date | date: 'dd MMMM YYYY' }}</b>
    </i>
    <hr />
  </div>
</div>

<ng-template #loadingOrError>
  <span *ngIf="errorMessage; else loading">
    An error occured while loading the posts: {{ errorMessage }}
  </span>
  <ng-template #loading> ...loading... </ng-template>
</ng-template>

State management, using RxJS | URL vs local client state

StackBlitz | Filter through RxJS

  • Related