Angular 파이프로 책갈피 목록을 쉽게 필터링하는 방법

최근에 Ctrl+h - History dialogBookmarks.dev 을 통해 최근에 방문한 북마크를 찾고 있습니다. 내 삶을 더 쉽게 만들기 위해 대화 상자에 필터 상자를 추가했습니다. 이제 하나 이상의 키워드를 추가하여 표시된 결과를 더 자세히 필터링할 수 있습니다. Pinned , ReadLater 또는 My Dashboard 과 같은 다른 책갈피 목록에 필터 상자를 추가했습니다.



이 블로그 게시물에서는 이 새로운 기능을 구현하는 데 필요한 Angular 구현을 소개합니다.

The source code for Bookmarks.dev is available on Github



북마크 필터 파이프 코드



필터링 기능을 구현하는 가장 쉬운 방법은 각진 파이프1를 사용하는 것입니다.

<mat-expansion-panel *ngFor="let bookmark of bookmarks | bookmarkFilter: filterText">


파이프의 전체 구현은 다음과 같습니다.

// bookmarks-filter.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
import { Bookmark } from '../core/model/bookmark';

@Pipe({name: 'bookmarkFilter'})
export class BookmarksFilterPipe implements PipeTransform {
  /**
   * Bookmarks in, bookmarks out that contain all the terms in the filterText
   *
   * @param {Bookmark[]} bookmarks
   * @param {string} filterText
   * @returns {Bookmark[]}
   */
  transform(bookmarks: Bookmark[], filterText: string): Bookmark[] {
    if (!bookmarks) {
      return [];
    }
    if (!filterText) {
      return bookmarks;
    }

    return bookmarks.filter(bookmark => {
      return this.bookmarkContainsFilterText(bookmark, filterText);
    });
  }

  private bookmarkContainsFilterText(bookmark: Bookmark, filterText): boolean {
    filterText = filterText.toLocaleLowerCase();
    const filterTerms = filterText.split(' ');
    for (const filterTerm of filterTerms) {
      const hasFilterTerm = this.bookmarkContainsFilterTerm(bookmark, filterTerm);
      if (hasFilterTerm === false) {
        return false;
      }
    }

    return true;
  }

  private tagsHaveFilterText(tags: string[], filterText: string): boolean {
    for (const tag of tags) {
      if (tag.includes(filterText)) {
        return true;
      }
    }

    return false;
  }

  private bookmarkContainsFilterTerm(bookmark: Bookmark, filterTerm: string) {
    return bookmark.name.toLocaleLowerCase().includes(filterTerm)
      || bookmark.location.toLocaleLowerCase().includes(filterTerm)
      || bookmark.description.toLocaleLowerCase().includes(filterTerm)
      || this.tagsHaveFilterText(bookmark.tags, filterTerm);
  }
}


책갈피의 제목, 위치, 태그 또는 설명에 filterText에 제공된 모든 필터 용어가 책갈피에 포함되어 있는지 확인합니다.

The filterText it's split into terms by spaces and all terms must be present



Angular History Dialog 컴포넌트에서의 사용법



다음은 기록 대화 상자 html 구성 요소에서 bookmarkFilter의 전체 사용법입니다.

<!--
 hot-keys-dialog.component.html
-->
<div class="dialog-title">
  <h2 mat-dialog-title [innerHTML]="title"></h2>
  <div class="form-group has-search">
    <span class="fas fa-filter form-control-feedback"></span>
    <input type="search" [(ngModel)]="filterText" class="form-control" placeholder="Filter...">
  </div>
</div>
<mat-dialog-content *ngIf="(bookmarks$ | async) as bookmarks" class="mt-2 pt-1 pb-1">
  <mat-accordion>
    <mat-expansion-panel *ngFor="let bookmark of bookmarks | bookmarkFilter: filterText">
      <mat-expansion-panel-header>
        <div class="p-3">
          <h5 class="card-title">
            <a href="{{bookmark.location}}"
               [innerHTML]="bookmark.name | slice:0:100 | highlightHtml: filterText"
               target="_blank"
               (click)="addToHistoryService.promoteInHistoryIfLoggedIn(true, bookmark)"
               (auxclick)="addToHistoryService.onMiddleClickInDescription(true, $event, bookmark)"
            >
              {{"see innerhtml"}}
            </a>
            <sup class="external-link-hint"><i class="fas fa-external-link-alt"></i></sup>
          </h5>
          <h6 class="card-subtitle mb-2 text-muted url-under-title"
              [innerHTML]="bookmark.location | slice:0:120 | highlightHtml: filterText"
          >
            {{"see innerhtml"}}
          </h6>
        </div>
      </mat-expansion-panel-header>

      <ng-template matExpansionPanelContent>
        <app-bookmark-text [bookmark]="bookmark"
                           (click)="addToHistoryService.onClickInDescription(true, $event, bookmark)"
                           (auxclick)="addToHistoryService.onMiddleClickInDescription(true, $event, bookmark)">
        </app-bookmark-text>
      </ng-template>
    </mat-expansion-panel>
  </mat-accordion>
</mat-dialog-content>

filterText 변수는 양방향 경계 변수 - <input type="search" [(ngModel)]="filterText" class="form-control" placeholder="Filter..."> 입니다.

html 입력 값은 이전에 본 것처럼 책갈피 필터 파이프라인의 필터 매개변수 필터입니다transform(bookmarks: Bookmark[], filterText: string): Bookmark[].

Note the highlight pipe chained to highlight the search terms: [innerHTML]="bookmark.name | slice:0:100 | highlightHtml: filterText"



구성 요소filterText에서 간단한 문자열 변수로 정의됩니다.

export class HotKeysDialogComponent implements OnInit {

  bookmarks$: Observable<Bookmark[]>;
  title: string;
  filterText: '';

  constructor(
    private dialogRef: MatDialogRef<HotKeysDialogComponent>,
    public addToHistoryService: AddToHistoryService,
    @Inject(MAT_DIALOG_DATA) data
  ) {
    this.bookmarks$ = data.bookmarks$;
    this.title = data.title;
  }

  ngOnInit() {
  }
}


보너스: 하이라이트 파이프



기록 대화 상자에서 필터 용어를 강조 표시하는 하이라이트 파이프의 구현을 아래에서 찾을 수 있습니다.

import {Pipe} from '@angular/core';
import {PipeTransform} from '@angular/core';

@Pipe({ name: 'highlightHtml' })
export class HighLightHtmlPipe implements PipeTransform {

  transform(text: string, search): string {
    if (!search || search === undefined) {
      return text;
    } else {
      let pattern = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
      pattern = pattern.split(' ').filter((t) => {
        return t.length > 0;
      }).join('|');
      pattern = '(' + pattern + ')' + '(?![^<]*>)';
      const regex = new RegExp(pattern, 'gi');

      return search ? text.replace(regex, (match) => `<span class="highlight">${match}</span>`) : text;
    }
  }

}


결론



이 게시물에서는 파이프를 사용하여 Angular에서 요소 목록을 동적으로 필터링하는 방법을 보았습니다.

If you have found this useful, please show some love and give us a star on Github



참조





https://angular.io/guide/pipes

좋은 웹페이지 즐겨찾기