Angular 为什么复选框[checked]为所有选项多次触发

Angular 为什么复选框[checked]为所有选项多次触发,angular,angular2-forms,Angular,Angular2 Forms,我正在创建一个具有复选框(多个选项)字段的表单。 我将在我的应用程序中的许多地方使用此类字段,这就是为什么我决定使用此功能的指令 我注意到Angular2没有很好地支持复选框(多个选项)。 因此,我使用复选框的[checked]选项来验证复选框是否选中,并使用(更改)来更新我的模型 在开发过程中,我注意到在点击复选框时-[checked]会多次触发,并且会选中所有选项,而不仅仅是我点击的这个选项 我创建了一个网站来告诉你我在说什么 我想知道为什么[checked]会多次开火(在这个plunkr中

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

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

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

我创建了一个网站来告诉你我在说什么


我想知道为什么
[checked]
会多次开火(在这个plunkr中是两次),而且它会检查所有选项,而不仅仅是单击的选项?

这是角度的工作原理。更改应用程序模型的某些部分时,Angular正在检查模型所在的“区域”(更复杂,应该在Angular中搜索区域)


[checked]
每次对每个选项运行更改检测时(对于每个事件或
setTimeout
或类似的异步调用),Angular2s更改检测都会调用
,以确定是否需要更新项的
checked
属性。

我已经在angular2中创建了Multicheckbox组件。请检查Plunker Url:

请在应用程序中导入此组件,并在所有位置多次使用

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

}
import{Component,Input,Output,EventEmitter,OnInit,OnChanges,changedtectionstrategy}来自'@angular/core';
从“@angular/core”导入{Pipe,PipeTransform};
声明var$:任何;
//var chkSelectedArr=[];
/**
*定义输入数据接口
*/
导出接口chkarray接口{
id:字符串;
标题:字符串;
}
/**
*选中复选框以创建数组
*/
@管道({name:'chkChecked',pure:false})
导出类ChkChecked实现PipeTransform{
转换(值,参数):任意{
如果(args!==未定义&&args.length!==0){
if(参数包括(值)){
返回true;
}否则{
返回false;
}
}
}
}
/**
*筛选复选框列表
*/
@管道({name:'filter',pure:true})
出口级过滤管{
转换(项目:任意[],参数:任意):任意{
让filter=args.toString();
if(filter!==undefined&&filter.length!==null){
if(filter.length==0 | | items.length==0){
退货项目;
}否则{
返回筛选器?items.filter(item=>item.title.toLocaleLowerCase().indexOf(filter)!=-1):项;
}
}
}
}
/**
*多选复选框组件
*/
@组成部分({
选择器:“多复选框”,
管道:[过滤器管道,CHK检查],
//changeDetection:ChangeDetectionStrategy.OnPush,
模板:`
全选
    {{chk?.title}
`, 风格:[` .自定义多复选框{ 边框:1px实心rgba(0,0,0,15); 边界半径:.25rem; 填充:5px0; 左:10px; 溢出:隐藏; 职位:相关职位 } .自定义列表框{ 保证金:10px 0px 10px 10px; 颜色:#0082c6; 溢出y:自动; } .自定义搜索框{ 利润率:7px; } 李{ 垫面:3件; 字体大小:400; 字体大小:.8125rem; } li>span{ 左边距:10px; } 全选{ 左边距:10px; 字体大小:粗体; 字体大小:.8125rem; } .input group加载项.glyphicon删除符号{ 光标:指针; } `] }) 导出类MultiCheckboxComponent实现OnInit、OnChanges{ @输入()chkArray:chkArray接口[]=[]; @Input()chkSelected:Array=[]; @Input()filtertite:string=“Filter”; @Input()isFilter:boolean=true; @输入()高度:string=“100px”; @Output()chkResult:EventEmitter=neweventemitter(); 私有txtSearch:string=“”; 私有chkSelectedArr:any[]=[]; 私有isSelectAll:布尔值; 私人Fiteredar:任何; 私人过滤管道:任何; 构造函数(){ this.isSelectalCheckbox(); } 恩戈尼尼特(){ } ngOnChanges(){ this.isSelectalCheckbox(); } /** *选中是否选择全部 */ isSelectAllCheckbox(){ 如果(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; }否则{ this.isSelectAll=false; } } } /** *选择全部,然后选中所有复选框 */ 选择全部(事件){ event.preventDefault(); this.filterPipe=新的filterPipe(); this.fiteredar=this.filterPipe.transform(this.chkArray,this.txtSearch); this.chkSelected=[]; this.isSelectAll=event.target.checked; if(this.fiteredar!==未定义&&event.target.checked==真&&this.fiteredar.length!==0){ this.fiteredar.forEach(chk=>{ this.chkSelected.push(chk.id); }); } this.chkResult.emit({ 值:this.chkSelected }) } /** *选中“垂直”复选框 */ 选择CHK(事件,val){ 如果(event.tar)