繁体   English   中英

Angular 2 过滤器/搜索列表

[英]Angular 2 filter/search list

我正在寻找 angular 2 的方式来做到这一点

我只有一个项目列表,我想输入一个输入,谁的工作是过滤列表。

<md-input placeholder="Item name..." [(ngModel)]="name"></md-input>

<div *ngFor="let item of items">
{{item.name}}
</div>

在 Angular 2 中这样做的实际方法是什么? 那需要管道吗?

按多个字段搜索

假设数据:

items = [
  {
    id: 1,
    text: 'First item'
  },
  {
    id: 2,
    text: 'Second item'
  },
  {
    id: 3,
    text: 'Third item'
  }
];

标记:

<input [(ngModel)]="query">
<div *ngFor="let item of items | search:'id,text':query">{{item.text}}</div>

管道:

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

@Pipe({
  name: 'search'
})
export class SearchPipe implements PipeTransform {
  public transform(value, keys: string, term: string) {

    if (!term) return value;
    return (value || []).filter(item => keys.split(',').some(key => item.hasOwnProperty(key) && new RegExp(term, 'gi').test(item[key])));

  }
}

一条线解决一切问题!

您必须通过将侦听器保持在input事件上来根据每次输入的变化手动过滤结果。 在进行手动过滤时,请确保您应该维护变量的两个副本,一个是原始集合副本,第二个是filteredCollection副本。 这样做的好处是可以节省您对变更检测周期进行的不必要的过滤。 您可能会看到更多代码,但这对性能更友好。

标记 - HTML 模板

<md-input #myInput placeholder="Item name..." [(ngModel)]="name" (input)="filterItem(myInput.value)"></md-input>

<div *ngFor="let item of filteredItems">
   {{item.name}}
</div>

代码

assignCopy(){
   this.filteredItems = Object.assign([], this.items);
}
filterItem(value){
   if(!value){
       this.assignCopy();
   } // when nothing has typed
   this.filteredItems = Object.assign([], this.items).filter(
      item => item.name.toLowerCase().indexOf(value.toLowerCase()) > -1
   )
}
this.assignCopy();//when you fetch collection from server.

HTML

<input [(ngModel)] = "searchTerm" (ngModelChange) = "search()"/>
<div *ngFor = "let item of items">{{item.name}}</div>

组件

search(): void {
    let term = this.searchTerm;
    this.items = this.itemsCopy.filter(function(tag) {
        return tag.name.indexOf(term) >= 0;
    }); 
}

请注意, this.itemsCopy等于this.items并且应该在进行搜索之前设置。

数据

names = ['Prashobh','Abraham','Anil','Sam','Natasha','Marry','Zian','karan']

您可以通过创建一个简单的管道来实现这一点

<input type="text" [(ngModel)]="queryString" id="search" placeholder="Search to type">

管道

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

@Pipe({
    name: 'FilterPipe',
})
export class FilterPipe implements PipeTransform {
    transform(value: any, input: string) {
        if (input) {
            input = input.toLowerCase();
            return value.filter(function (el: any) {
                return el.toLowerCase().indexOf(input) > -1;
            })
        }
        return value;
    }
}

这将根据搜索词过滤结果

更多信息

在 angular 2 中,我们没有像 AngularJs 那样预定义的过滤器和排序依据,我们需要根据我们的要求创建它。 这是消磨时间,但我们需要这样做,(参见 No FilterPipe 或 OrderByPipe)。 在本文中,我们将看到如何在 angular 2 中创建名为 pipe 的过滤器和名为 Order By 的排序功能。 让我们为它使用一个简单的虚拟 json 数据数组。 这是我们将用于示例的 json

首先,我们将通过使用搜索功能来了解如何使用管道(过滤器):

创建一个名为 category.component.ts 的组件

 import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-category', templateUrl: './category.component.html' }) export class CategoryComponent implements OnInit { records: Array<any>; isDesc: boolean = false; column: string = 'CategoryName'; constructor() { } ngOnInit() { this.records= [ { CategoryID: 1, CategoryName: "Beverages", Description: "Coffees, teas" }, { CategoryID: 2, CategoryName: "Condiments", Description: "Sweet and savory sauces" }, { CategoryID: 3, CategoryName: "Confections", Description: "Desserts and candies" }, { CategoryID: 4, CategoryName: "Cheeses", Description: "Smetana, Quark and Cheddar Cheese" }, { CategoryID: 5, CategoryName: "Grains/Cereals", Description: "Breads, crackers, pasta, and cereal" }, { CategoryID: 6, CategoryName: "Beverages", Description: "Beers, and ales" }, { CategoryID: 7, CategoryName: "Condiments", Description: "Selishes, spreads, and seasonings" }, { CategoryID: 8, CategoryName: "Confections", Description: "Sweet breads" }, { CategoryID: 9, CategoryName: "Cheeses", Description: "Cheese Burger" }, { CategoryID: 10, CategoryName: "Grains/Cereals", Description: "Breads, crackers, pasta, and cereal" } ]; // this.sort(this.column); } }
 <div class="col-md-12"> <table class="table table-responsive table-hover"> <tr> <th >Category ID</th> <th>Category</th> <th>Description</th> </tr> <tr *ngFor="let item of records"> <td>{{item.CategoryID}}</td> <td>{{item.CategoryName}}</td> <td>{{item.Description}}</td> </tr> </table> </div>

2. 这段代码没有什么特别之处,只是用一个类别列表初始化我们的记录变量,声明了另外两个变量 isDesc 和 column,我们将用于后者的排序。 最后添加了 this.sort(this.column); 后者我们将使用,一旦我们拥有这种方法。

注意 templateUrl: './category.component.html',我们接下来将创建它以显示表格格式的记录。

为此,创建一个名为 category.component.html 的 HTML 页面,其中包含以下代码:

3.这里我们使用ngFor来重复记录并逐行显示,尝试运行它,我们可以看到一个表中的所有记录。

搜索 - 过滤记录

假设我们要按类别名称搜索表格,为此我们添加一个文本框来键入和搜索

 <div class="form-group"> <div class="col-md-6" > <input type="text" [(ngModel)]="searchText" class="form-control" placeholder="Search By Category" /> </div> </div>

5.现在我们需要创建一个管道来按类别搜索结果,因为过滤器不再像在angularjs中那样可用。

创建一个文件 category.pipe.ts 并在其中添加以下代码。

 import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'category' }) export class CategoryPipe implements PipeTransform { transform(categories: any, searchText: any): any { if(searchText == null) return categories; return categories.filter(function(category){ return category.CategoryName.toLowerCase().indexOf(searchText.toLowerCase()) > -1; }) } }

6.在转换方法中,我们接受类别列表和搜索文本以搜索/过滤列表上的记录。 把这个文件导入到我们的category.component.ts文件中,我们这里要使用它,如下:

 import { CategoryPipe } from './category.pipe'; @Component({ selector: 'app-category', templateUrl: './category.component.html', pipes: [CategoryPipe] // This Line })

7.我们的 ngFor 循环现在需要我们的 Pipe 来过滤记录,因此将其更改为这个。您可以在下图中看到输出

在此处输入图片说明

您还可以创建一个搜索管道来过滤结果:

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

@Pipe({
  name : 'searchPipe',
})
export class SearchPipe implements PipeTransform {
  public transform(value, key: string, term: string) {
    return value.filter((item) => {
      if (item.hasOwnProperty(key)) {
        if (term) {
          let regExp = new RegExp('\\b' + term, 'gi');
          return regExp.test(item[key]);
        } else {
          return true;
        }
      } else {
        return false;
      }
    });
  }
}

在 HTML 中使用管道:

<md-input placeholder="Item name..." [(ngModel)]="search" ></md-input>
<div *ngFor="let item of items | searchPipe:'name':search ">
  {{item.name}}
</div>

Angular 2+ 中的管道是直接从模板转换和格式化数据的好方法。

管道允许我们更改模板内的数据; 即过滤、排序、格式化日期、数字、货币等。一个简单的例子是您可以通过在模板代码中应用一个简单的过滤器将字符串转换为小写。

来自API 列表示例的内置管道列表

{{ user.name | uppercase }}

Angular 版本 4.4.7 的示例。 ng version


接受多个参数的自定义管道

HTML « *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] "
TS   « transform(json: any[], args: any[]) : any[] { ... }

使用管道过滤内容« json-filter-by.pipe.ts

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

@Pipe({ name: 'jsonFilterBy' })
@Injectable()
export class JsonFilterByPipe implements PipeTransform {

  transform(json: any[], args: any[]) : any[] {
    var searchText = args[0];
    var jsonKey = args[1];

    // json = undefined, args = (2) [undefined, "name"]
    if(searchText == null || searchText == 'undefined') return json;
    if(jsonKey    == null || jsonKey    == 'undefined') return json;

    // Copy all objects of original array into new Array.
    var returnObjects = json;
    json.forEach( function ( filterObjectEntery ) {

      if( filterObjectEntery.hasOwnProperty( jsonKey ) ) {
        console.log('Search key is available in JSON object.');

        if ( typeof filterObjectEntery[jsonKey] != "undefined" && 
        filterObjectEntery[jsonKey].toLowerCase().indexOf(searchText.toLowerCase()) > -1 ) {
            // object value contains the user provided text.
        } else {
            // object didn't match a filter value so remove it from array via filter
            returnObjects = returnObjects.filter(obj => obj !== filterObjectEntery);
        }
      } else {
        console.log('Search key is not available in JSON object.');
      }

    })
    return returnObjects;
  }
}

添加到@NgModule « 将JsonFilterByPipe添加到模块的声明列表中; 如果你忘记这样做,你会得到一个错误 no provider for jsonFilterBy 如果您添加到模块,则该模块的所有组件都可以使用它。

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    FormsModule, ReactiveFormsModule,
  ],
  providers: [ StudentDetailsService ],
  declarations: [
    UsersComponent, UserComponent,

    JsonFilterByPipe,
  ],
  exports : [UsersComponent, UserComponent]
})
export class UsersModule {
    // ...
}

文件名: users.component.tsStudentDetailsService是从此链接创建的。

import { MyStudents } from './../../services/student/my-students';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { StudentDetailsService } from '../../services/student/student-details.service';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: [ './users.component.css' ],

  providers:[StudentDetailsService]
})
export class UsersComponent implements OnInit, OnDestroy  {

  students: MyStudents[];
  selectedStudent: MyStudents;

  constructor(private studentService: StudentDetailsService) { }

  ngOnInit(): void {
    this.loadAllUsers();
  }
  ngOnDestroy(): void {
    // ONDestroy to prevent memory leaks
  }

  loadAllUsers(): void {
    this.studentService.getStudentsList().then(students => this.students = students);
  }

  onSelect(student: MyStudents): void {
    this.selectedStudent = student;
  }

}

文件名: users.component.html

<div>
    <br />
    <div class="form-group">
        <div class="col-md-6" >
            Filter by Name: 
            <input type="text" [(ngModel)]="searchText" 
                   class="form-control" placeholder="Search By Category" />
        </div>
    </div>

    <h2>Present are Students</h2>
    <ul class="students">
    <li *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] " >
        <a *ngIf="student" routerLink="/users/update/{{student.id}}">
            <span class="badge">{{student.id}}</span> {{student.name | uppercase}}
        </a>
    </li>
    </ul>
</div>

试试这个html 代码

<md-input #myInput placeholder="Item name..." [(ngModel)]="name"></md-input>

<div *ngFor="let item of filteredItems | search: name">
   {{item.name}}
</div>

使用搜索管道

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

@Pipe({
  name: 'search'
})
export class SearchPipe implements PipeTransform {

  transform(value: any, args?: any): any {

    if(!value)return null;
    if(!args)return value;

    args = args.toLowerCase();

    return value.filter(function(item){
        return JSON.stringify(item).toLowerCase().includes(args);
    });
}

}

对@Mosche 的回答稍作修改,以便在不存在过滤器元素的情况下进行处理。

TS :

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

@Pipe({
    name: 'filterFromList'
})
export class FilterPipe implements PipeTransform {
    public transform(value, keys: string, term: string) {

        if (!term) {
            return value
        }
        let res = (value || []).filter((item) => keys.split(',').some(key => item.hasOwnProperty(key) && new RegExp(term, 'gi').test(item[key])));
        return res.length ? res : [-1];

    }
}

现在,在您的 HTML 中,您可以通过“-1”值进行检查,但没有结果。

HTML :

<div *ngFor="let item of list | filterFromList: 'attribute': inputVariableModel">
            <mat-list-item *ngIf="item !== -1">
                <h4 mat-line class="inline-block">
                 {{item}}
                </h4>
            </mat-list-item>
            <mat-list-item *ngIf="item === -1">
                No Matches
            </mat-list-item>
        </div>

这段代码几乎对我有用……但我想要一个多元素过滤器,所以我对过滤器管道的修改如下:

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

@Pipe({ name: 'jsonFilterBy' })
@Injectable()
export class JsonFilterByPipe implements PipeTransform {

  transform(json: any[], args: any[]): any[] {
    const searchText = args[0];
    const jsonKey = args[1];
    let jsonKeyArray = [];

    if (searchText == null || searchText === 'undefined') { return json; }

    if (jsonKey.indexOf(',') > 0) {
        jsonKey.split(',').forEach( function(key) {
            jsonKeyArray.push(key.trim());
        });
    } else {
        jsonKeyArray.push(jsonKey.trim());
    }

    if (jsonKeyArray.length === 0) { return json; }

    // Start with new Array and push found objects onto it.
    let returnObjects = [];
    json.forEach( function ( filterObjectEntry ) {

        jsonKeyArray.forEach( function (jsonKeyValue) {
            if ( typeof filterObjectEntry[jsonKeyValue] !== 'undefined' &&
            filterObjectEntry[jsonKeyValue].toLowerCase().indexOf(searchText.toLowerCase()) > -1 ) {
                // object value contains the user provided text.
                returnObjects.push(filterObjectEntry);
                }
            });

    });
    return returnObjects;
  }
} 

现在,而不是

jsonFilterBy:[ searchText, 'name']

你可以

jsonFilterBy:[ searchText, 'name, other, other2...']
<md-input placeholder="Item name..." [(ngModel)]="name" (keyup)="filterResults()"></md-input>

<div *ngFor="let item of filteredValue">
{{item.name}}
</div>

  filterResults() {
    if (!this.name) {
      this.filteredValue = [...this.items];
    } else {
      this.filteredValue = [];
      this.filteredValue = this.items.filter((item) => {
        return item.name.toUpperCase().indexOf(this.name.toUpperCase()) > -1;
      });
    }
 }

不要对“项目”数组(从中过滤结果的项目列表)做任何修改。 当搜索的项目 'name' 为空时,返回完整的 'items' 列表,如果不是,则将 'name' 与 'items' 数组中的每个 'name' 进行比较,并仅过滤掉存在于 'items' 数组中的名称和将其存储在“filteredValue”中。

目前ng2-search-filter简化了这项工作。

按指令

<tr *ngFor="let item of items | filter:searchText">
  <td>{{item.name}}</td>
</tr>

或以编程方式

let itemsFiltered = new Ng2SearchPipe().transform(items, searchText);

实际例子: https : //angular-search-filter.stackblitz.io

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM