web-dev-qa-db-ja.com

Angular 4 Pipe Filter

カスタムパイプを使用して、ngModelの入力フィールドを使用して*ngForループをフィルター処理しようとしています。私の他のカスタムパイプ(sortBy)では、完全に機能します。ただし、フィルターパイプにより、データがまったく表示されないように見えます。私はまだこれを学んでいます、そして私は役に立たないいくつかのバリエーションを試しました:

-filter: term
-filter: {{term}}
-filter: 'term'
-filter" {{'term'}}

したがって、問題はコードの他の場所にある可能性があると思います。誰か助けてくれたら本当に感謝しています。

ここに私のコードがあります:

HTMLコンポーネント

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!!
  </h1>

</div>
<h2>Please choose your favorite song: </h2>
<form id="filter">
    <label>Filter people by name:</label>
    <input type="text" name="term" [(ngModel)]="term" />
</form>


<table class="table">
    <thead>
      <tr>
        <th>Title</th>
        <th>Artist</th>
        <th>Likes</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let song of songs | filter:term| sortBy: 'likes'; let i  = index">
        <td>{{song.title}}</td>
        <td>{{song.artist}}</td>
        <td>{{song.likes}} 

            <i class="fa fa-heart-o" aria-hidden="true"  *ngIf="song.likes < 1"></i>
         <i class="fa fa-heart" aria-hidden="true" *ngIf="song.likes >= 1"></i>
             <i class="fa fa-plus" aria-hidden="true" (click)="addLike(i)" ></i>
            <i class="fa fa-minus" aria-hidden="true" (click)="removeLike(i)" ></i>

          </td>
      </tr>
    </tbody>
  </table>

パイプ

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

@Pipe({
    name: 'filter',
    pure: false
})

export class FilterPipe implements PipeTransform {
    transform(items: any[], args: any[]): any {
        return items.filter(item => item.id.indexOf(args[0]) !== -1);
    }
}

モジュール

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { SortByPipe } from './sort-by.pipe';
import { FilterPipe } from './filter.pipe';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Pipe, PipeTransform } from '@angular/core'; 


@NgModule({
  declarations: [
    AppComponent,
    SortByPipe,
   FilterPipe
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

JSコンポーネント

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'Oxcord';
  songs = [

  {title: "Song", artist: "Artist", likes: 1},
  {title: "Chanson", artist: "Artiste", likes: 3},
  {title: "ABC", artist: "OneTwoThree", likes: 2},
  {title: "Trash", artist: "Meek Mill", likes: 0}

  ];
  addLike(input){
  this.songs[input].likes +=1;
} 
removeLike(input){
  this.songs[input].likes -=1;
} 
args="Me";
}
24
user3523602

これは、フィルターとsortByパイプを備えた作業用プランカーです。 https://plnkr.co/edit/vRvnNUULmBpkbLUYk4uw?p=preview

Developer033がコメントで述べたように、フィルターパイプが値の配列を予期している場合、単一の値をフィルターパイプに渡します。配列ではなく単一の値を期待するようにパイプに指示します

export class FilterPipe implements PipeTransform {
    transform(items: any[], term: string): any {
        // I am unsure what id is here. did you mean title?
        return items.filter(item => item.id.indexOf(term) !== -1);
    }
}

DeborahKには、パフォーマンス上の理由から不純なパイプを避ける必要があることに同意します。 plunkrには、不純なパイプがどれだけ呼び出されたかを確認できるコンソールログが含まれています。

20
LLai

変換メソッドのシグネチャは、Angular 2.のRCのどこかで変更されました。次のようなものを試してください。

export class FilterPipe implements PipeTransform {
    transform(items: any[], filterBy: string): any {
        return items.filter(item => item.id.indexOf(filterBy) !== -1);
    }
}

また、nullを処理し、フィルターの大文字と小文字を区別しないようにしたい場合は、ここにあるようなものを実行できます。

export class ProductFilterPipe implements PipeTransform {

    transform(value: IProduct[], filterBy: string): IProduct[] {
        filterBy = filterBy ? filterBy.toLocaleLowerCase() : null;
        return filterBy ? value.filter((product: IProduct) =>
            product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1) : value;
    }
}

注:パイプでの並べ替えとフィルタリングはパフォーマンスの大きな問題であり、は推奨されません。詳細については、こちらのドキュメントを参照してください: https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

10
DeborahK

パイプ in 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;
  }
}

Add to@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>
1
Yash

私はこれが古いことを知っていますが、私は良い解決策があると思います。他の回答と比較し、受け入れられたものと比較しても、私のものは複数の値を受け入れます。基本的に、key:value検索パラメーター(オブジェクト内のオブジェクト)でオブジェクトをフィルターします。また、数値などで機能し、比較するときに、文字列に変換します。

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

@Pipe({name: 'filter'})
export class Filter implements PipeTransform {
    transform(array: Array<Object>, filter: Object): any {
        let notAllKeysUndefined = false;
        let newArray = [];

        if(array.length > 0) {
            for (let k in filter){
                if (filter.hasOwnProperty(k)) {
                    if(filter[k] != undefined && filter[k] != '') {
                        for (let i = 0; i < array.length; i++) {
                            let filterRule = filter[k];

                            if(typeof filterRule === 'object') {
                                for(let fkey in filterRule) {
                                    if (filter[k].hasOwnProperty(fkey)) {
                                        if(filter[k][fkey] != undefined && filter[k][fkey] != '') {
                                            if(this.shouldPushInArray(array[i][k][fkey], filter[k][fkey])) {
                                                newArray.Push(array[i]);
                                            }
                                            notAllKeysUndefined = true;
                                        }
                                    }
                                }
                            } else {
                                if(this.shouldPushInArray(array[i][k], filter[k])) {
                                    newArray.Push(array[i]);
                                }
                                notAllKeysUndefined = true;
                            }
                        }
                    }
                }
            }
            if(notAllKeysUndefined) {
                return newArray;
            }
        }

        return array;
    }

    private shouldPushInArray(item, filter) {
        if(typeof filter !== 'string') {
            item = item.toString();
            filter = filter.toString();
        }

        // Filter main logic
        item = item.toLowerCase();
        filter = filter.toLowerCase();
        if(item.indexOf(filter) !== -1) {
            return true;
        }
        return false;
    }
}
0
Andris