在 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
}
管道有两种类型:纯管道和非纯管道。有关 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);
});
}
}
这个管道定义揭示了以下几个关键点:
- 管道是一个用管道元数据装饰的类。
- 管道类实现了 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 { }
现在我们可以在 中使用过滤管道了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>
// 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',
...
]
}
但是嘿!我们的搜索结果没有像一开始那样突出显示😟
原因是Pipes
Angular 只会将传递给它的数据转换为所需的输出,而不会操作与之关联的 HTML。为了突出显示搜索结果,我们需要操作 HTML 来突出显示searchText
其中的一部分。这可以使用 来实现Directives
。
Angular 中的指令
Angular 指令用于通过赋予 HTML 新语法来扩展其功能。指令有 3 种类型:
- 组件——带有模板的指令。
- 结构指令——通过添加和删除 DOM 元素来更改 DOM 布局。
- 属性指令——改变元素、组件或其他指令的外观或行为。
涵盖指令超出了本文的讨论范围。如果您想了解有关 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>`);
}
}
逻辑是通过
<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 { }
为了在 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>
现在,我们就能看到所需的输出了!😌
您可以查看我的GitHub repo来了解此帖子的完整实现。
下次再见!
鏂囩珷鏉ユ簮锛�https://dev.to/idrisrampurawala/creating-a-search-filter-in-angular-562d