web-dev-qa-db-ja.com

Angular 2でngFor内のすべてのフィルタリングされたチェックボックスを選択する方法は?

*ngFor内のチェックボックスのリストをロードしてユーザーに表示するAngular 2コンポーネントがあります。リストは、キーに基づいてフィルタリングすることもできます。すべてを選択する必要があります。フィルタリングされたアイテムを配列に追加します。すべてのチェックボックスをオンにできますが、問題としてcheckedを変更すると、changeイベントが発生しません。これを修正する方法はありますか?

テンプレート:

<div class="form-group">
    <input type="text" class="form-control" id="stringKeyFilter" placeholder="Key Filter"
           [(ngModel)]="keyFilter">
</div>

<table class="table table-striped table-hover">
    <thead>
    <tr>
        <th>Id</th>
        <th style="width: 150px;">Action</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let device of devices| stringFilter: keyFilter">
        <td>
            {{device.$key}}
        </td>
        <td>
            <div class="checkbox">
                <label> <input type="checkbox"
                               [checked]="selectAll || selectedDevices.indexOf(device.$key) > -1"
                               (change)="updateSelectedDevices(device.$key, $event)" > View</label>
            </div>
        </td>
    </tr>
    </tbody>
</table>

<div class="btn-group pull-right">
    <button type="button" class="btn btn-primary" (click)="selectAllDevices()">Select All</button>
    <button type="button" class="btn btn-default" (click)="deselectAllDevices()">Deselect All
    </button>
</div>

成分:

@Component({
    moduleId: module.id,
    selector: 'device-list',
    template: template
})
export class DeviceListComponent implements OnInit {
    devicesObservable: FirebaseListObservable<Device[]>;
    devices: Device[] = [];
    isLoading: boolean = true;
    selectedDevices: string[] = [];
    selectAll: boolean = false;
    allCtrl: any;

    keyFilter: string = '';

    constructor(private af: AngularFire) {

    }

    ngOnInit(): void {


        this.devicesObservable = this.af.database.list('/online', {
            query: {
                orderByKey: true,
            }
        });
        this.devicesObservable.subscribe((devicesData)=> {
            this.devices = devicesData;
            this.isLoading = false
        });
    }

    updateSelectedDevices(deviceId: string, event): void {
        if (event.target.checked) {
            this.selectedDevices.Push(deviceId);
        }
        else {
            _.pull(this.selectedDevices, deviceId);
        }
    }


    loadingDeviceDetail(loading: boolean): void {
        this.isLoading = loading;
    }

    selectAllDevices(): void {
        this.selectAll = true;
    }

    deselectAllDevices(): void {
        this.selectAll = false;
        this.selectedDevices = [];
    }

}

enter image description here

enter image description here

14
ePezhman

更新

フィルタリングされたリストのすべてのチェックボックスをデモ選択/選択解除するようにサンプルコードとプランカーを更新しました。


私の理解によると、フィルターの動作はAngular1からAngular2に変更されました。

Angular1では、データまたはフィルターパラメーターが変更されると、DOM(Webページ)が再計算されます。 (私はこれについて間違っているかもしれませんが、ずっと前に:P)

Angular2では、要するに、data(array)を変更してもフィルター計算がトリガーされないため、新しい結果やDOMの更新はありません。

長くて公式な説明はここにあります: Angular2 Pipes --ts 。テンプレート内でpipe(filter)を使用することを主張する場合は、ドキュメントの不純なpipeセクションを調べる必要があります。

別の解決策は、*ngForでフィルターを使用しないことです。代わりに、フィルタリングされたリストを作成してください。

プランカー

http://plnkr.co/edit/pEpaj0?p=preview

サンプルコード

app.component.ts

import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {

  title='How to select all filtered checkboxes inside ngFor in Angular 2?';
  url='http://stackoverflow.com/questions/39703103/';

  device = [
    {'name':'abc','checked':false},
    {'name':'abcd','checked':false},
    {'name':'abcde','checked':false},
    {'name':'abc123','checked':false},
    {'name':'abc1234','checked':false}];

  deviceFilter = '';

  deviceFiltered = this.device.slice(0);

  selectFiltered(){
    this.deviceFiltered.forEach(i=>i.checked=true);
  }

  deSelectFiltered(){
    this.deviceFiltered.forEach(i=>i.checked=false);
  }

  onFilterChange(){
    if (this.deviceFilter.length > 0) {
      this.deviceFiltered = this.device.filter(i => i.name.indexOf(this.deviceFilter) > -1);
      console.log(this.deviceFiltered);
    } else {
      this.deviceFiltered = this.device.slice(0);
    }
  }
}

app.component.html

<h2><a [href]="titleUrl">{{title}}</a></h2>

<div>
  Filter
  <input [(ngModel)]="deviceFilter" (ngModelChange)="onFilterChange()">
</div>

<div>
  List:
  <ul>
    <li *ngFor="let i of device">
      <input type="checkbox" [(ngModel)]="i.checked">{{i.name}}
    </li>
  </ul>
</div>

<div>
  Filtered List:
  <ul>
    <li *ngFor="let i of deviceFiltered">
      <input type="checkbox" [(ngModel)]="i.checked">{{i.name}}
    </li>
  </ul>
  <button (click)="selectFiltered()">Select Filtered</button>
  <button (click)="deSelectFiltered()">Deselect Filtered</button>
</div>
6
John Siu

すべてのデバイスを選択しようとすると、メインリストは更新されず、何も変更されず、angularはデバイスの変更を検出しません(更新されたフラグがありますが、リストは同じ)。2つのオプションがあります。

  1. リストのチェックされたすべての要素にフラグを付けます。
  2. ApplicationRef.tick()を使用して手動レンダリングをトリガーします https://angular.io/docs/ts/latest/api/core/index/ApplicationRef-class.html#!#tick-anchor
3
jordic

注:動作するアプリのみを取得するためにいくつかの変更を加えたため、コードが異なる場合があります。コードスニペットから関連部分を取得して適用してください。

これがあなたの質問のための作業コードです。

以下は、コードに加える必要のある変更です。

<input type="checkbox"  [checked]="selectedDevices.indexOf(device.$key) > -1"
                               (change)="updateSelectedDevices(device.$key, $event)" >

すべて選択機能を次のように変更します。

selectAllDevices(): void {
    this.selectedDevices = this.strFilter(this.devices, this.keyFilter).map(dev=>dev.$key); 
  }

注意: this.strFilterは、コンポーネントクラス/関数のフィルター関数です。これは、Filterクラスによって異なります。私はこのようなフィルター/パイプを作成しました。

//stringfilter.pipe.ts

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

@Pipe({name: 'stringFilter'})
export class StringFilter implements PipeTransform {
  transform(value: Array<any>, filterKey: string): Array<any> {
    return (
      filterKey ? value.
        filter(el => (el.name).toLowerCase().includes(filterKey))
        : value
    );
  }
}

コンポーネントクラスでは、//コンポーネントクラスが好きでした

import {StringFilter} from './filter-file'

そして

ngOnInit(): void {

    this.strFilter = new StringFilter().transform;
    //this.devices = [];
    this.isLoading = false;

  }

次のコードをテストしました。これで問題が解決することを願っています。

1
lokeshjain2008