问题描述
我正在尝试使用ng-select和controlValueAccessor
界面来包装设置multiselect(使用每个选项的复选框)组合所需的所有配置。
到目前为止,它还可以工作,除了如果我通过列表顶部的复选框选择选择或取消选择所有项目,则仅更新表单中的值,而不更新控件中的选择。
仅当我分别选择或取消选择项目时,控件才能按预期工作,然后控件和表单值都会相应更新:
以下是可重试组件的代码:
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];
}