在 Angular 中创建搜索过滤器

2025-06-08

在 Angular 中创建搜索过滤器

假设我们在 UI 上向用户显示一长串数据。如果没有搜索功能,用户在这长串数据中搜索任何特定关键词都会非常繁琐。因此,为了方便用户,我们通常会在 UI 上实现搜索过滤器。

角度过滤器演示

那么现在的问题是,如何实现它?其实很简单 😉 我们想要的只是一个过滤器,它接受一个数组作为输入,并根据我们提供的条件返回该数组的子集。在 Angular 中,这种将数据转换为其他形式的方式是用 实现的。在开始实现之前,Pipes我们先来了解一下。pipes


Angular 中的管道

管道接收数据作为输入,并将其转换为所需的输出。管道既可以在 HTML 模板表达式中使用,也可以在组件中使用。Angular 提供了一些内置管道,例如 CurrencyPipe、DatePipe、DecimalPipe 等。查看下面的代码片段来查看其实际运行情况。



dateObj = Date.now();

// HTML template expression syntax using pipe operator (|)
{{ dateObj | date }}               // output is 'Jun 15, 2015'
{{ dateObj | date:'medium' }}      // output is 'Jun 15, 2015, 9:43:11 PM'
{{ dateObj | date:'shortTime' }}   // output is '9:43 PM'
{{ dateObj | date:'mm:ss' }}       // output is '43:11'

// Using in component
constructor(private datePipe: DatePipe) { 
    console.log(datePipe.transform(Date.now(),'yyyy-MM-dd'));
    //2019-07-22
}


Enter fullscreen mode Exit fullscreen mode

管道有两种类型:纯管道和非纯管道。有关 Angular 管道的更多信息,请访问此链接


实现搜索过滤器

1.创建过滤管道

让我们用过滤器的代码填充管道。复制并粘贴此代码到filter.pipe.ts



// filter.pipe.ts

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

@Pipe({ name: 'appFilter' })
export class FilterPipe implements PipeTransform {
  /**
   * Pipe filters the list of elements based on the search text provided
   *
   * @param items list of elements to search in
   * @param searchText search string
   * @returns list of elements filtered by search text or []
   */
  transform(items: any[], searchText: string): any[] {
    if (!items) {
      return [];
    }
    if (!searchText) {
      return items;
    }
    searchText = searchText.toLocaleLowerCase();

    return items.filter(it => {
      return it.toLocaleLowerCase().includes(searchText);
    });
  }
}


Enter fullscreen mode Exit fullscreen mode

这个管道定义揭示了以下几个关键点:

  • 管道是一个用管道元数据装饰的类。
  • 管道类实现了 PipeTransform 接口的 transform 方法,该方法接受一个输入值和后跟的可选参数,并返回转换后的值。在我们的过滤管道中,它接受两个输入——一个用于过滤数组的输入array和一个search text用于过滤数组的输入。
  • 为了告诉 Angular 这是一个管道,我们应用了@Pipe decorator从核心 Angular 库导入的。
  • @Pipe 装饰器允许我们定义在模板表达式中使用的管道名称。它必须是有效的 JavaScript 标识符。我们的管道名称是appFilter

2. 使用管道

要使用管道,首先我们需要将其导入到 app 模块中。我们的app.module.ts文件现在如下所示:



// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

import { FilterPipe } from './pipes/filter.pipe'; // -> imported filter pipe

@NgModule({
  declarations: [
    AppComponent,
    FilterPipe // -> added filter pipe to use it inside the component
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }


Enter fullscreen mode Exit fullscreen mode

现在我们可以在 中使用过滤管道了App Component。假设在我们的 中app.component.html有一个输入框,我们可以在其中输入我们的数据searchText,以及一个利用它pipe来过滤结果的列表。



<!-- app.component.html -->

<div class="content" role="main">
  <div class="card">
    <div class="form-group">
      <label for="search-text">Search Text</label>
      <input type="email" class="form-control" id="search-text" aria-describedby="search-text" 
        [(ngModel)]="searchText" placeholder="Enter text to search" 
        autofocus>
    </div>
    <ul class="list-group list-group-flush">
      <!-- results of ngFor is passed to appFilter with argument searchText -->
      <li class="list-group-item" *ngFor="let c of characters | appFilter: searchText">
        {{c}}
      </li>
    </ul>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode


// app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'angular-text-search-highlight';
  searchText = '';
  characters = [
    'Ant-Man',
    'Aquaman',
    'Asterix',
    'The Atom',
    'The Avengers',
    'Batgirl',
    'Batman',
    'Batwoman',
    ...
  ]
}


Enter fullscreen mode Exit fullscreen mode

就是这样!现在,当我们运行应用程序时,我们将看到以下输出:
角度过滤器输出

但是嘿!我们的搜索结果没有像一开始那样突出显示😟

原因是PipesAngular 只会将传递给它的数据转换为所需的输出,而不会操作与之关联的 HTML。为了突出显示搜索结果,我们需要操作 HTML 来突出显示searchText其中的一部分。这可以使用 来实现Directives


Angular 中的指令

Angular 指令用于通过赋予 HTML 新语法来扩展其功能。指令有 3 种类型:

  1. 组件——带有模板的指令。
  2. 结构指令——通过添加和删除 DOM 元素来更改 DOM 布局。
  3. 属性指令——改变元素、组件或其他指令的外观或行为。

涵盖指令超出了本文的讨论范围。如果您想了解有关 Angular 指令的更多信息,请访问此链接


在我们的应用程序中实施指令

在我们的例子中,我们将使用来attribute directive突出显示searchText结果列表中的。

1. 创建高亮指令

属性型指令至少需要构建一个使用 @Directive 注解的控制器类,该控制器类指定用于标识属性的选择器。该控制器类实现所需的指令行为。

让我们用高亮代码填充指令。复制并粘贴此代码到highlight.pipe.ts



// highlight.directive.ts

import { Directive, Input, SimpleChanges, Renderer2, ElementRef, OnChanges } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective implements OnChanges {
  @Input() searchedWord: string; // searchText
  @Input() content: string; // HTML content
  @Input() classToApply: string; //class to apply for highlighting
  @Input() setTitle = false; //sets title attribute of HTML

  constructor(private el: ElementRef, private renderer: Renderer2) { }

  ngOnChanges(changes: SimpleChanges): void {
    if (!this.content) {
      return;
    }

    if (this.setTitle) {
      this.renderer.setProperty(
        this.el.nativeElement,
        'title',
        this.content
      );
    }

    if (!this.searchedWord || !this.searchedWord.length || !this.classToApply) {
      this.renderer.setProperty(this.el.nativeElement, 'innerHTML', this.content);
      return;
    }

    this.renderer.setProperty(
      this.el.nativeElement,
      'innerHTML',
      this.getFormattedText()
    );
  }

  getFormattedText() {
    const re = new RegExp(`(${this.searchedWord})`, 'gi');
    return this.content.replace(re, `<span class="${this.classToApply}">$1</span>`);
  }
}


Enter fullscreen mode Exit fullscreen mode

逻辑是通过<span>在之间添加标签searchText并应用突出显示类来操作当前 HTML 元素。

2. 使用指令

要使用管道,首先我们需要将其导入到 app 模块中。我们的app.module.ts文件现在如下所示:



// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

import { HighlightDirective } from './directives/highlight.directive'; // ->  imported directive
import { FilterPipe } from './pipes/filter.pipe';

@NgModule({
  declarations: [
    AppComponent,
    HighlightDirective, // -> added directive
    FilterPipe
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Enter fullscreen mode Exit fullscreen mode

为了在 HTML 文件中使用此指令,我们需要将其添加为包含所有参数的普通 HTML 属性。如下所示:



<!-- app.component.html -->

<div class="content" role="main">
  <div class="card">
    <div class="form-group">
      <label for="search-text">Search Text</label>
      <input type="email" class="form-control" id="search-text" aria-describedby="search-text" 
        [(ngModel)]="searchText" placeholder="Enter text to search" 
        autofocus>
    </div>
    <ul class="list-group list-group-flush">
      <li class="list-group-item" *ngFor="let c of characters | appFilter: searchText"
        appHighlight [searchedWord]="searchText" [content]="c"  
        [classToApply]="'font-weight-bold'" [setTitle]="'true'">
        {{c}}
      </li>
    </ul>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

现在,我们就能看到所需的输出了!😌


您可以查看我的GitHub repo来了解此帖子的完整实现。

下次再见!

鏂囩珷鏉ユ簮锛�https://dev.to/idrisrampurawala/creating-a-search-filter-in-angular-562d
PREV
Git 和 GitHub - 完整指南 - 第 1 章:Git 入门
NEXT
Flutter 初学者指南