angular - 为什么重置自定义 Angular 反应式表单控件会显示不一致的行为?
问题描述
我有一个使用反应形式的 Angular (v10) 项目。有一个自定义的多选组件,实现ControlValueAccessor
.
一切正常,但在父组件中重置控件的行为很奇怪:
// This doesn't reset the value correctly. With the debugger I found out, that Angular updates
// the value correctly at some point, but after the call, the value is still/again the old one.
this.myMultiselect.reset({value: [], disabled: true});
// Splitting the reset and disabling, it works the expected way.
this.myMultiselect.reset([]);
this.myMultiselect.disable();
有具体原因吗?它是一个错误吗?我们想在任何地方都使用相同的样式(具有值/禁用的对象),但我不明白,为什么它不适用于我们的自定义组件。
其他表单控件与这两种变体都可以正常工作。
多选.component.ts
import {Component, forwardRef, Input, OnDestroy, OnInit} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
import {takeUntil} from 'rxjs/operators';
import {ReplaySubject, Subject} from 'rxjs';
import {MultiselectOption} from './multiselect-option';
@Component({
selector: 'eb-multiselect',
templateUrl: './multiselect.component.html',
styleUrls: ['./multiselect.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => MultiselectComponent)
}
]
})
export class MultiselectComponent implements OnInit, OnDestroy, ControlValueAccessor {
@Input() withFilter = false;
@Input() withSelectButtons = false;
_options: MultiselectOption[];
@Input()
set options(value: MultiselectOption[]) {
this._options = value;
this.filteredOptions.next(this._options.slice());
}
@Input() labelText: string;
selectControl = new FormControl();
searchControl = new FormControl();
filteredOptions: ReplaySubject<MultiselectOption[]> = new ReplaySubject<MultiselectOption[]>(1);
protected _onDestroy = new Subject<void>();
ngOnInit() {
this.filteredOptions.next(this._options?.slice());
this.searchControl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
this.filterOptions();
});
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
}
filterOptions() {
if (!this._options) {
return;
}
let search = this.searchControl.value;
if (!search) {
this.filteredOptions.next(this._options.slice());
return;
} else {
search = search.toLowerCase();
}
this.filteredOptions.next(this._options.filter(option => option.name.toLowerCase().indexOf(search) !== -1));
}
selectAll() {
this.selectControl.setValue(this._options.map(o => o.value));
}
deselectAll() {
this.selectControl.setValue([]);
}
writeValue(value: any): void {
this.selectControl.setValue(value);
}
registerOnChange(fn: (value: any) => void): void {
this.selectControl.valueChanges.subscribe(fn);
}
registerOnTouched(): void {}
setDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.selectControl.disable();
} else {
this.selectControl.enable();
}
}
}
多选.component.html
<mat-form-field>
<mat-label>{{ labelText }}</mat-label>
<mat-select [formControl]="selectControl" disableOptionCentering multiple>
<mat-option *ngIf="withFilter">
<ngx-mat-select-search [formControl]="searchControl"></ngx-mat-select-search>
</mat-option>
<div *ngIf="withSelectButtons" class="select-buttons">
<button mat-button (click)="selectAll()">Select all</button>
<button mat-button (click)="deselectAll()">Deselect all</button>
</div>
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">{{ option.name }}</mat-option>
</mat-select>
</mat-form-field>
解决方案
推荐阅读
- javascript - ThreeJS ExtrudeGeometry HOLE 从点
- angular - 如何检查组件输入值是否已更改或未更改
- ruby-on-rails - Capistrano 3 错误 - extconf.rb:29:in `
':“libxml2”包不可用。(运行时错误) - kubernetes - Kubernetes:无法获取 GCE GCECloudProvider 并出现错误
- python-3.x - 使用 Python 从 AWS S3 下载文件
- swift - 在另一个字典上使用字典的键崩溃
- node.js - 使本地主机端口可通过互联网访问 - NodeJS
- c# - “粘贴”操作后未引发“操作完成”事件
- python - “双”迭代器和生成器函数
- angularjs - 通过输入使 AngularJS 服务动态化