Ng-Select-使用ControlValueAccessor界面选择/取消选择自定义组件中的所有项目

问题描述

我正在尝试使用ng-select和controlValueAccessor界面来包装设置multiselect(使用每个选项的复选框)组合所需的所有配置。

到目前为止,它还可以工作,除了如果我通过列表顶部的复选框选择选择或取消选择所有项目,则仅更新表单中的值,而不更新控件中的选择。

enter image description here

仅当我分别选择或取消选择项目时,控件才能按预期工作,然后控件和表单值都会相应更新:

enter image description here

以下是可重试组件的代码

TypeScript

import { Component,Input,OnInit,Self,ViewChild } from '@angular/core';
import { ControlValueAccessor,NgControl } from '@angular/forms';

@Component({
  selector: 'app-multi-select',templateUrl: './multi-select.component.html',styleUrls: ['./multi-select.component.css']
})
export class MultiSelectComponent implements OnInit,ControlValueAccessor {

  disabled: boolean;
  selectedValues: any;

  @input() optionItems: any[];
  @ViewChild('combo',{ static: true }) combo;
  constructor(@Self() public controlDir: NgControl) {
    this.controlDir.valueAccessor = this;
  }

  ngOnInit(): void {
  }

  toggleCheckAll(values: any) {
    if (values.currentTarget.checked) {
      this.selectAllItems();
    } else {
      this.unselectAllItems();
    }
  }
  onChange(event) {
    debugger;
  }

  onTouched() {}

  onSelectionChange(selectedItems) {
    debugger;
    if (Array.isArray(selectedItems)) {
      const newList = selectedItems.map((x) => x.id);
      this.selectedValues = [...newList]
      this.onChange([...newList]);
    }
    this.onTouched();
  }

  writeValue(obj: any): void {
    this.combo.select([...obj]);
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setdisabledState?(isdisabled: boolean): void {
    this.disabled = isdisabled;
  }

  private selectAllItems() {
    const newList = this.optionItems.map((x) => x.id);
    this.selectedValues = [...newList];
    this.onChange([...newList]);
  }

  private unselectAllItems() {
    this.selectedValues = [];
    this.onChange([]);
  }

}

HTML

<ng-select 
  #combo
  [multiple]="true" 
  [items]="optionItems"
  [cloSEOnSelect]="false"
  (change)="onSelectionChange($event)"   
  (blur)="onTouched()"    
  placeholder="Select people"
    bindLabel="name"
  bindValue="id">

    <ng-template ng-header-tmp let-items="items">
        <input type="checkBox"  (change)="toggleCheckAll($event)"/>
        </ng-template>

        <ng-template ng-multi-label-tmp let-items="items" let-clear="clear">
            <div class="ng-value" *ngFor="let item of items | slice:0:2">
                <span class="ng-value-label">{{item.name}}{{item.login}}</span>
                <span class="ng-value-icon right" (click)="clear(item)" aria-hidden="true">×</span>
            </div>
            <div class="ng-value" *ngIf="items.length > 2">
                <span class="ng-value-label">{{items.length - 2}} more...</span>
            </div>
        </ng-template>

        <ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index">
            <input id="item-{{index}}" type="checkBox" [checked]="item$.selected" /> {{item.name}}
    </ng-template>
</ng-select>

您可以在this demo on stackblitz

中找到完整的代码

顺便说一句:我必须在条件onSelectionChange中放入一个条件,以检查传入的参数是否为数组,因为令我惊讶的是,即使使用复选框,change事件也会被调用不仅在我选择或取消选择各个选项时都位于列表的顶部。

解决方法

您可以使用ngModel指令将所选值绑定到ng-select。

尝试一下:

<ng-select #combo [multiple]="true" [items]="optionItems" [closeOnSelect]="false" (change)="onSelectionChange($event)"
    (blur)="onTouched()" placeholder="Select people" bindLabel="name" [ngModel]="selectedValues" bindValue="id">

    <ng-template ng-header-tmp let-items="items">
        <input type="checkbox" [ngModel]="checkAll"  (change)="toggleCheckAll($event)"/>
        </ng-template>

        <ng-template ng-multi-label-tmp let-items="items" let-clear="clear">
            <div class="ng-value" *ngFor="let item of items | slice:0:2">
                <span class="ng-value-label">{{item.name}}{{item.login}}</span>
                <span class="ng-value-icon right" (click)="clear(item)" aria-hidden="true">×</span>
            </div>
            <div class="ng-value" *ngIf="items.length > 2">
                <span class="ng-value-label">{{items.length - 2}} more...</span>
            </div>
        </ng-template>

        <ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index">
            <input id="item-{{index}}" type="checkbox" [checked]="item$.selected" /> {{item.name}}
    </ng-template>
</ng-select>

然后在您的班级中将值设置为selectedValue,如下所示:

component.ts

 writeValue(obj: any): void {
    this.selectedValues =[...obj];
  }