首页 文章

如何在Angular 2中选择ngFor中的所有过滤复选框?

提问于
浏览
14

我有一个Angular 2组件,它在 *ngFor 中加载并显示用户的复选框列表,也可以根据键过滤列表 . 我需要选择所有过滤的项目并将它们添加到数组中 . 我可以检查所有复选框,但问题是当我更改 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

3 回答

  • 1

    更新

    更新了示例代码和plunker以演示选择/取消选中已筛选列表的所有复选框 .


    根据我的理解,过滤器行为从Angular1变为Angular2 .

    在Angular1中,当修改数据或过滤器参数时,将重新计算DOM(网页) . (我可能在很久以前就错了:P)

    在Angular2中,简而言之,修改数据(数组)不会触发过滤器计算,因此没有新结果,也没有更新到DOM .

    长官方解释如下:Angular2 Pipes - ts . 如果您坚持在模板中使用管道(过滤器),则应浏览文档中的 impure pipe 部分 .

    另一种解决方案是不使用带有 *ngFor 的过滤器 . 改为创建筛选列表 .

    Plunker

    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

    当您尝试选择所有设备时,主列表未更新,没有任何更改,角度也没有检测到它的更改 . (有一个更新的标志,但列表是相同的) . 您有两种选择:

  • 3

    注意:您的代码可能会有所不同,因为我做了一些更改才能获得正常工作的应用 . 请从代码片段中获取相关部分并申请 .

    这是您的问题的工作代码 .

    以下是您需要对代码进行的更改 .

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

    我测试了以下代码 . 希望这能解决你的问题 .

相关问题