Angular(5) - 对两级数组数据使用相同的管道

时间:2018-02-27 11:09:06

标签: angular typescript pipe

我正在尝试为两级json数据实现相同的管道,我在两个嵌套的ngFor循环中用html解析。

home.component.html:

<div class="drop-type">
<div class="label">Multi-select two levels</div>

<div class="search-input-box">
  <input [(ngModel)]="searchValue" class="search-input" placeholder="Search...">

  <div *ngIf="searchValue && searchValue.length > 1" class="ac-list">
    <ul>
      <ng-container *ngFor="let value of values | value: searchValue">
        <li class="drop-item" (click)="selectMSTLItem(value)">
          <div class="check" [ngClass]="{'selected': value.selected}"></div>
          <div class="name">{{value.name}}</div>
        </li>
        <ng-container *ngFor="let subvalue of value.subitems | value: searchValue">
          <li class="drop-item sub-item" (click)="selectMSTLItem(subvalue)">
            <div class="check" [ngClass]="{'selected': subvalue.selected}"></div>
            <div class="name">{{subvalue.name}}</div>
          </li>
        </ng-container>
      </ng-container>
    </ul>
  </div>
</div>

<ng-container *ngFor="let selectedItem of values">
  <div class="selected-drop-item">
    <div *ngIf="selectedItem.selected" (click)="deselectMSTLItem(selectedItem)">{{selectedItem.name}}</div>
  </div>
  <ng-container *ngFor="let selectedSubItem of selectedItem.subitems">
    <div class="selected-drop-item">
      <div *ngIf="selectedSubItem.selected" (click)="deselectMSTLItem(selectedSubItem)">{{selectedSubItem.name}}</div>
    </div>
  </ng-container>
</ng-container></div>

home.component.ts:

import { Component, OnInit } from '@angular/core';
import {ValuesService} from './values.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.less']
})
export class HomeComponent implements OnInit {
  values: any[] = [];
  searchValue: string;

  constructor(private valuesService: ValuesService) {
  }

  ngOnInit() {
    this.valuesService.getValues()
      .subscribe(
        (response) => {
          this.values = response.results;
        },
        (error) => {
          console.log(error);
        }
      );
  }

  selectMSTLItem(selectedItem) {
    selectedItem.selected = !selectedItem.selected;
  }

  deselectMSTLItem(selectedItem) {
    selectedItem.selected = false;
  }
}

search.pipe.ts:

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

@Pipe({name: 'value'})
export class SearchPipe implements PipeTransform {
  transform(values: any, searchValue: any): any {
    if (searchValue == null) { return values; }

    return values.filter(function(value){
      return value.name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1
        || value.subitems.name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
    });
  }
}

values.service.ts:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class ValuesService {
  private _url = '../assets/values.json';

  constructor(private _http: Http) {}

  getValues () {
    return this._http.get(this._url)
      .map((response: Response) => response.json());
  }
}

values.json:

    {
  "results": [
    {
      "name": "Value 1.0",
      "selected": false,
      "subitems": [
        {
          "name": "Value 1.1",
          "selected": false
        },
        {
          "name": "Value 1.2",
          "selected": false
        },
        {
          "name": "Value 1.3",
          "selected": false
        }
      ]
    },
    {
      "name": "Value 2.0",
      "subitems": [
        {
          "name": "Value 2.1",
          "selected": false
        },
        {
          "name": "Value 2.2",
          "selected": false
        },
        {
          "name": "Value 2.3",
          "selected": false
        }
      ]
    },
    {
      "name": "Value 3.0",
      "subitems": [
        {
          "name": "Value 3.1",
          "selected": false
        },
        {
          "name": "Value 3.2",
          "selected": false
        },
        {
          "name": "Value 3.3",
          "selected": false
        }
      ]
    }
  ]
}

我想要完成的是,例如,当用户输入字符串“Va”时,它会列出包含字符串“va”的所有1级和2级名称值,现在它会执行此操作。但是,当用户想要搜索2级元素并输入字符串“Value 1”时。 (搜索值1.1或值1.2等)我收到错误

  

TypeError:无法读取未定义的属性'toLowerCase'

在第二个返回值的管道中(value.subitems.name.toLowerCase()。indexOf(searchValue.toLowerCase())&gt; -1)

我的猜测是我需要以某种方式在管道中循环遍历所有2级元素,并过滤掉那些包含搜索值的元素,然后返回那些以及所有1级元素。有人可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

value.subitems是您无法访问的数组value.subitems.name 试试这个:

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

@Pipe({name: 'value'})
export class SearchPipe implements PipeTransform {
  transform(values: any[], searchValue: any): any {
    if (searchValue == null) { return values; }

    return values.filter(v => this.filterFn(v, searchValue));
  }

  filterFn(value: any, searchValue) {
    let flag = this.testSearchCondition(value.name, searchValue);
    if (!flag && value.subitems) {
      flag = value.subitems.filter(v => this.testSearchCondition(v.name, searchValue)).length > 0;
    }
    return flag;
  }
  testSearchCondition(name: string, searchValue: string): boolean {
    return name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
  }
}

答案 1 :(得分:1)

嵌套数组搜索使用以下代码 这里data.sub_categories是嵌套数组

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

@Pipe({
    name: 'category'
})
export class CategoryPipe implements PipeTransform {

    transform(value: any, args?: any): any {
        if (args === undefined || args === '') { return value; }
        return value.filter(data => { 
          return  data.category_name.toLowerCase().includes(args.toLowerCase())  || data.sub_categories.find(item => item.category_name.toLowerCase().includes(args.toLowerCase()));

        });
    }

}