Угловой 2 фильтр / список поиска

Я ищу угловой 2 способ сделать это.

У меня просто есть список элементов, и я хочу внести свой вклад, чья работа состоит в том, чтобы отфильтровать список.

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

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

Каков реальный способ сделать это в Angular 2? Это требует трубы?

9 ответов

Решение

Вы должны вручную фильтровать результат на основе изменения входных данных каждый раз, удерживая слушателя над 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.

Поиск по нескольким полям

Предполагая данные:

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])));

  }
}

Одна строка для всего!

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 у нас нет предопределенного фильтра и порядка, как это было с AngularJ, нам нужно создать его для наших требований. Время убивать, но нам нужно это сделать (см. No FilterPipe или OrderByPipe). В этой статье мы рассмотрим, как мы можем создать фильтр под названием pipe в angular 2 и функцию сортировки под названием 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. Ничего особенного в этом коде просто инициализируйте нашу переменную records списком категорий, объявлены две другие переменные isDesc и column, которые мы будем использовать для сортировки последних. В конце добавлен this.sort(this.column); последний мы будем использовать, как только у нас будет этот метод.

Обратите внимание на templateUrl: "./category.component.html", который мы создадим рядом, чтобы показать записи в табличном формате.

Для этого создайте HTML-страницу под названием category.component.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 }}

Пример угловой версии 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 в ваш список объявлений в вашем модуле; если вы забудете это сделать, вы получите сообщение об ошибке 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>

попробуйте этот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);
    });
}

}

В настоящее время 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

<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;
      });
    }
 }

Не вносите никаких изменений в массив 'items' (список элементов, по которым фильтруются результаты). Когда искомый элемент 'name' пуст, верните полный список 'items', если не сравните 'name' с каждым 'name' в массиве 'items' и отфильтруйте только имя, которое присутствует в массиве 'items' и сохраните его в filterValue.

Небольшая модификация ответа @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...']
Другие вопросы по тегам