为什么Checkbox [checked]为所有选项多次触发

时间:2016-09-13 05:19:00

标签: angular angular2-forms

我正在创建一个带有复选框(多个选项)字段的表单 我将在我的应用程序中的许多地方使用这种类型的字段,这就是为什么我决定使用指令来实现此功能。

我注意到Angular2不是很好地支持复选框(多个选项) 因此我使用[checked]选项来复选框以验证复选框是否已选中,(change)更新我的模型。

在开发过程中,我注意到单击复选框时,[checked]会多次触发,并且还会检查所有选项,而不仅仅是我点击的选项。

我创建了一个plunkr来向您展示我正在谈论的内容。

我想知道为什么[checked]多次触发(在这个plunkr中两次)并且它检查所有选项而不仅仅是点击的那个?

3 个答案:

答案 0 :(得分:1)

Angular是如何运作的。您更改了应用程序模型的某些部分,Angular正在检查"区域"模型所在的位置(它更复杂,你应该在Angular中搜索区域)。

http://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html

http://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html

答案 1 :(得分:1)

每次更改检测运行时(每个事件或[checked]或类似的异步调用),Angular2s更改检测都会调用

setTimeout,以确定每个选项的checked属性是否为const timeToWait : number = 500; const keyDigitsUp$ = Observable.fromEvent(document, "keyup") .filter((event:any) => {return ((event.keyCode>=48 && event.keyCode <=57) || (event.keyCode>=96 && event.keyCode <=106))}); let bufferedEvents = Observable.from(keyDigitsUp$).bufferCount(2); let numbers : string = ""; bufferedEvents.subscribe((eventArray) => { if (eventArray[1].timeStamp - eventArray[0].timeStamp <= timeToWait) { numbers+=eventArray[0].key + eventArray[1].key; } else { numbers=""; } }); 属性。项目需要更新。

答案 2 :(得分:1)

我在angular2中创建了Multicheckbox组件。请检查Plunker网址:Plunker Here

请在您的应用程序中导入此组件,并多次使用它。

1)multicheckbox.ts

import {Component, Input, Output, EventEmitter, OnInit, OnChanges, ChangeDetectionStrategy} from '@angular/core';
import {Pipe, PipeTransform} from "@angular/core";

declare var $:any;
//var chkSelectedArr=[];

/**
 * Define input data interface
 */
export interface chkArrayInterface {
  id: string;
  title: string;
}

/**
 * checked checkbox to array
 */
@Pipe({ name: 'chkChecked', pure: false })
export class ChkChecked implements PipeTransform {
    transform(value, args): any {
        if(args !== undefined && args.length !== 0){
            if(args.includes(value)){
                return true;
            }else{
                return false;
            }
        }
    }
}

/**
 * filter checkbox list
 */
@Pipe({ name: 'filter', pure: true })
export class FilterPipe{
  transform(items: any[], args: any): any {
    let filter = args.toString();
    if(filter !== undefined && filter.length !== null){
        if(filter.length === 0 || items.length ===0){
            return items;
        }else{
            return filter ? items.filter(item=> item.title.toLocaleLowerCase().indexOf(filter) != -1) : items;
        }
    }
  }
}

/**
 * Multi select checkbox component
 */
@Component({
    selector: 'multi-checkbox',
    pipes: [FilterPipe, ChkChecked],
    //changeDetection: ChangeDetectionStrategy.OnPush,
    template : `
    <div class="custom-multicheck-box">
        <div class="input-group custom-search-box" *ngIf="isFilter">
            <div class="input-group-addon">
                <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
            </div>
            <input type="text" class="form-control"  (keyup)="changeFilter()" (input)="txtSearch = $event.target.value" [value]="txtSearch" [placeholder]="filterTitle" />
            <div class="input-group-addon" (click)="resetSearch()">
                <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
            </div>
        </div>
        <div class="custom-list-box" [style.height]="height">
        <input type="checkbox" [checked]="isSelectAll" (change)="selectAll($event)" />
        <span class="select-all">Select All</span>
        <ul>
            <li *ngFor="let chk of chkArray | filter:txtSearch">
                <input type="checkbox" [checked]="chk.id | chkChecked: chkSelected " (change)="selectChk($event,chk.id)" />
                <span>{{chk?.title}}</span>
            </li>
        </ul>
        </div>
    </div>
    `,

    styles: [`
        .custom-multicheck-box { 
            border: 1px solid rgba(0,0,0,.15);
            border-radius: .25rem;
            padding: 5px 0;
            left: 10px;
            overflow: hidden;
            position: reletive
        }

        .custom-list-box {
            margin: 10px 0px 10px 10px;
            color: #0082c6;
            overflow-y: auto;
        }

        .custom-search-box {
            margin: 7px;
        }

        li {
            padding-top: 3px;
            font-weight: 400;
            font-size: .8125rem;
        }

        li > span {
            margin-left:10px;
        }

        span.select-all {
            margin-left:10px;
            font-weight: bold;
            font-size: .8125rem;
        }

        .input-group-addon .glyphicon-remove-sign {
            cursor: pointer;
        }
    `]
})

export class MultiCheckboxComponent implements OnInit, OnChanges  { 
    @Input() chkArray: chkArrayInterface[]=[];
    @Input() chkSelected: Array<any>=[];
    @Input() filterTitle: string="Filter";
    @Input() isFilter: boolean=true;
    @Input() height: string="100px";
    @Output() chkResult: EventEmitter<any> = new EventEmitter();
    private txtSearch:string="";
    private chkSelectedArr:any[]=[];
    private isSelectAll:boolean;
    private fiteredArr:any;
    private filterPipe:any;
    constructor() {
        this.isSelectAllCheckbox();
    }

    ngOnInit() {
    }

    ngOnChanges(){
        this.isSelectAllCheckbox();
    }

    /**
     * Checked is selectAll or not
     */
    isSelectAllCheckbox(){
        if(this.chkArray !== undefined && this.chkArray !== null 
           && this.chkSelected !== undefined && this.chkSelected!==null){

            if(this.chkArray.length === this.chkSelected.length && this.chkArray.length !==0){
                this.isSelectAll = true;
            }else{
                this.isSelectAll = false;
            }
        }
    }

    /**
     * Select all then all checkbox selected
     */
    selectAll(event) {
        event.preventDefault();
        this.filterPipe = new FilterPipe();
        this.fiteredArr = this.filterPipe.transform(this.chkArray,this.txtSearch);

        this.chkSelected = [];
        this.isSelectAll = event.target.checked;
        if(this.fiteredArr !== undefined && event.target.checked === true && this.fiteredArr.length !==0){
            this.fiteredArr.forEach(chk => {
                this.chkSelected.push(chk.id);
            });
        }

        this.chkResult.emit({
          value: this.chkSelected
        })
    }

    /**
     * Select perticular checkbox
     */
    selectChk(event, val){
        if(event.target.checked === true){
            this.chkSelected.push(val);
        }else{
            var index = this.chkSelected.indexOf(val);
            this.chkSelected.splice(index, 1);
        }

        this.isSelectAllCheckbox();

        this.chkResult.emit({
          value: this.chkSelected
        })
    }

    /**
     * Reset filter checkbox
     */
    resetSearch(){
        this.txtSearch="";
        this.changeFilter();
    }

    /**
     * Check on filter selected all or not
     */
    changeFilter(){
         this.filterPipe = new FilterPipe();
        this.fiteredArr = this.filterPipe.transform(this.chkArray,this.txtSearch);
        if(this.fiteredArr !== undefined && this.chkSelected !== undefined){
            if(this.fiteredArr.length === this.chkSelected.length && this.fiteredArr.length !== 0){
                this.isSelectAll = true;
            }else{
                this.isSelectAll = false;
            }
        }
    }

}