我正在寻找Angular 2的方法来完成这个。
我有一个项目列表,我想创建一个输入框来筛选该列表。
<md-input placeholder="Item name..." [(ngModel)]="name"></md-input>
<div *ngFor="let item of items">
{{item.name}}
</div>
在Angular 2中,实际的做法是什么?需要使用管道吗?
我正在寻找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])));
}
}
万事一行!
[(ngModel)]="query"
附加到单选按钮上?类似这样?
<input [(ngModel)]="query" type="radio" name="topic.term" [value]="topic.term"/>{{topic.term}}
- Towelie您需要通过在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.
item.name...
改成了 !item.name
,现在可以搜索了。唯一的问题是,如果我输入的是“BOX”,而有一个名为“BLACK BOX”的物品,它将不会显示出来,因为“BOX”是第二个单词(它只从第一个单词开始搜索,而不是所有单词)。你有什么想法吗? - TheUnrealitem.property
只过滤一个属性,可以使用 JSON.stringify(item)
并使用其中的所有属性。 - ZahemaHTML
<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,在进行搜索之前应该先设置它。
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页面,以表格形式显示记录。
为此,请创建一个名为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. 在transform方法中,我们接受类别列表和搜索文本来搜索/过滤列表上的记录。将此文件导入到我们的category.component.ts文件中,我们希望在此处使用它,如下所示:
import { CategoryPipe } from './category.pipe';
@Component({
selector: 'app-category',
templateUrl: './category.component.html',
pipes: [CategoryPipe] // This Line
})
7.我们的ngFor循环现在需要使用管道来过滤记录,因此请将其更改为以下内容。您可以在下面的图像中查看输出。
<tr *ngFor="let item of records | search : searchText">
请将其添加到 .html 文件中。你能提供另一种多级筛选的解决方案吗? - Prasanna数据
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;
}
}
您还可以创建一个搜索管道来过滤结果:
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+中的管道是一种很好的方式,可以直接从模板中转换和格式化数据。
管道允许我们在模板内部更改数据;例如过滤、排序、格式化日期、数字、货币等。一个快速的例子是通过在模板代码中应用简单的过滤器将字符串转换为小写。
{{ user.name | uppercase }}
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;
}
}
将JsonFilterByPipe
添加到模块的声明列表中;如果忘记这样做,将会出现jsonFilterBy
提供程序错误。 如果添加到模块,则可用于该模块中的所有组件。
@NgModule({
imports: [
CommonModule,
RouterModule,
FormsModule, ReactiveFormsModule,
],
providers: [ StudentDetailsService ],
declarations: [
UsersComponent, UserComponent,
JsonFilterByPipe,
],
exports : [UsersComponent, UserComponent]
})
export class UsersModule {
// ...
}
文件名:users.component.ts
,StudentDetailsService
是从这个链接创建的。
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>
<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);
});
}
}
这段代码对我来说几乎可以工作...但是我想要一个多元素过滤器,所以我对过滤管道进行了修改:
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...']
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];
}
}
<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>