在 Angular 中使用管道仅搜索一个字段

Search Only One Field Using Pipe In Angular

我的 JSON 中有这个项目列表,我只想搜索项目名称而忽略其他字段。我现在的问题是它还搜索其他字段。我怎样才能只在我的管道中使用项目名称进行搜索而不影响它的其他字段。下面是我所做的。

JSON

{
  "token": "ejsk0e",
  "projects": [
    {
      "id": 5,
      "name": "Store",
      "description": "Small",
      "organization_id": 1,
      "created_at": "2017-10-29 10:31:50",
      "updated_at": "2017-11-14 06:27:03",
      "material_projects": [
        {
          "id": 18,
          "material_id": 40,
          "project_id": 5,
          "quantity": 10,
          "unit": "pcs",
          "created_at": "2017-11-02 09:57:14",
          "updated_at": "2017-11-02 09:57:14",
          "material": {
            "id": 40,
            "sku": "ACWNAIL",
            "name": "Banana",
            "created_at": "2017-10-26 03:19:54",
            "updated_at": "2017-10-26 03:23:21"
          },
          "categories": [
            {
              "id": 8,
              "name": "Fruits",
              "created_at": "2017-10-26 07:36:48",
              "updated_at": "2017-11-10 02:06:07",
              "pivot": {
                "material_proj_id": 18,
                "category_id": 8
              }
            }
          ],
          "material_name": "Banana",
          "material_sku": "ACWNAIL",
          "category_name": "Fruits"
        }
  ]
}

TS

 getAllProjects() {
    this.subscription = this.projectsService.getAll()
      .subscribe(
        (data:any) => {
          this.projects = data.projects;
        },
        error => {
          console.log(error);
        });
  }

HTML

<div class="container-fluid">
  <input placeholder="Search..."" type="text" [(ngModel)]="searchProj">
  <div class="row" *ngFor="let project of projects | search : searchProj">
    <div class="card-block">
      <h2 class="proj-name">{{ project.name }}</h2>
    </div>
  </div>
</div>

PIPE.ts

export class SearchPipe implements PipeTransform {

      transform(items: any, term: any): any {
        if (term === undefined) return items;

        return items.filter(function(item) {
          for(let property in item){
            if (item[property] === null){
              continue;
            }
            if(item[property].toString().toLowerCase().includes(term.toLowerCase())){
              return true;
            }
          }
          return false;
        });
      }
    }

您的问题的解决方案是将 属性 作为变量输入您的管道:

transform(items: any, term: any, prop: string): any {
    if (!term || !prop) return items;

    return items.filter((item) => 
        item[prop].toString().toLowerCase().includes(term.toLowerCase()));
  }


<div class="row" *ngFor="let project of projects | search : searchProj : 'name'">

然而...

您永远不应该在管道转换中进行排序和过滤之类的操作。管道转换在每个变化检测周期触发,这是非常频繁的,这导致排序和过滤在每个变化检测周期重新应用,无论是否需要,这导致应用程序性能极差。事实上,angularJS 包含一个过滤器管道,但由于广泛滥用导致应用程序性能不佳,它被删除了。更好的方法是建立在您需要触发排序或过滤时自己的逻辑,而不是依赖变化检测来为您完成。

使用响应式表单比使用 ngModel 更容易,因此我的示例将使用它。

TS:

this.projects$ = this.projectsService.getAll();
this.searchProj = new FormControl('');
this.search$ = this.searchProj.valueChanges.startWith('').debounce(300).distinctUntilChanged();
this.filteredProjects$= Observable.combineLatest(this.projects$, this.search$)
                                  .map(([projects, searchTerm]) => (searchTerm) ? projects.filter(p => p.name.toString().toLowerCase().includes(searchTerm.toLowerCase()) : projects);

那么你的 html:

<div class="container-fluid">
  <input placeholder="Search..."" type="text" [formControl]="searchProj">
  <div class="row" *ngFor="let project of filteredProjects$ | async">
    <div class="card-block">
      <h2 class="proj-name">{{ project.name }}</h2>
    </div>
  </div>
</div>

为了引导您完成这段代码,首先您将用于检索项目的服务方法存储在一个可观察对象中,然后为您的搜索词创建一个表单控件,然后将其值更改方法存储在一个可观察对象中,告诉它首先从一个空值开始,然后去抖动它,只得到 distnct 值(这是一个小的优化,所以如果用户快速输入,你实际上只搜索每两个字符,如果他们快速输入和删除一个字符,则不研究).然后将这两个组合到一个新的 observable 中,并将它们映射到您的过滤函数中,这样每次项目发生变化时都会过滤项目。

至于你原来的问题...现在这不是一个因素,因为你没有使用像管道一样通用的东西,你可以明确过滤名称 属性,或者你可以把上面的转换函数用在你的地图运算符中,如果你经常使用它,就不会重复过滤逻辑。