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

Posted

技术标签:

【中文标题】如何在Angular 2中选择ngFor中的所有过滤复选框?【英文标题】:How to select all filtered checkboxes inside ngFor in Angular 2? 【发布时间】:2017-02-03 19:30:33 【问题描述】:

我有一个 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 = [];
    


【问题讨论】:

你的问题不够清楚。你被困在哪里了? 问题是当我更改 checked 有问题时,更改事件不会触发 您尚未将复选框与模型绑定。使用 ngModel 然后它应该会正常运行。 【参考方案1】:

当您尝试选择所有设备时,您的主列表不会更新,没有任何变化,并且 Angular 不会检测到它的变化。 (有一个更新的标志,但列表是相同的)。你有两个选择:

    在列表中每个选中的元素上放置一个标志。 触发手动渲染 ApplicationRef.tick() https://angular.io/docs/ts/latest/api/core/index/ApplicationRef-class.html#!#tick-anchor

【讨论】:

感谢您的回复,但是没有一个建议可以解决我的问题,问题是过滤的项目没有反映在组件中,所以我不知道要标记哪些项目。 过滤器只是一个函数,为什么不将它应用到列表中,然后标记项目。类似于:var a = new searchFilter() result = a.transform(this.devices, this.keyFilter); result.forEach((i)=&gt; this.selectedDevices.push(i.$key) )【参考方案2】:

更新

更新了示例代码和 plunker 以演示选择/取消选择过滤列表的所有复选框。


据我了解,过滤器行为从 Angular1 更改为 Angular2。

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

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

详细的官方解释在这里:Angular2 Pipes - ts。如果您坚持在模板中使用管道(过滤器),您应该探索文档中的 不纯管道 部分。

另一个解决方案是不使用带有*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://***.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>

【讨论】:

【参考方案3】:

注意:您的代码可能会有所不同,因为我进行了一些更改以仅获得一个工作应用程序。请从代码sn-ps中获取相关部分并申请。

这是您问题的工作代码。

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

<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 是组件类/函数中的过滤函数。 这取决于您的过滤器类。我已经创建了这样的过滤器/管道。

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

  

我已经测试了以下代码。希望这能解决您的问题。

【讨论】:

以上是关于如何在Angular 2中选择ngFor中的所有过滤复选框?的主要内容,如果未能解决你的问题,请参考以下文章

*ngFor 如何与 Angular 2 中的模板变量一起工作?

Angular2,Ionic2:如何使用 ngModel 对嵌套 *ngfor 中的单选按钮进行 2way 绑定?

如何在 ngFor angular 2 内部使用 track

带有 ngFor 输入的 Angular 2 模板驱动表单

Angular ViewChildren 不会立即看到来自 ngFor 的所有孩子

如何使 div 中的 flexbox 具有 2 列与 mat-chips/angular material2 的 ngFor?