javascript - 在 Angular Material 自定义字段组件中禁用不起作用
问题描述
我有一个使用 Angular Material 创建的自定义滑动切换组件。我遵循了本指南:https ://material.angular.io/guide/creating-a-custom-form-field-control
一切似乎都工作正常,除非我像这样动态禁用自定义组件:
<custom-slide-toggle
[toggleClass]="'enable_user'"
[value]="userFormGroup.get('activeUser').value"
formControlName="activeUser"
[toggleText]="'enable user'"
(selectionChange)="statusChange()"
[isChecked]="userFormGroup.get('activeUser').value"
[required]="false"
[disabled]="true"
></custom-slide-toggle>
该组件已禁用,但我收到控制台警告 It looks like you're using the disabled attribute with a reactive form directive. ...
。
为了解决它,我尝试像这样设置禁用推荐的方式:activeUser: new FormControl([{value:false, disabled: true}])
在父组件中,但自定义组件没有被禁用。
我也尝试了同样的事情,但在自定义组件本身中,但对禁用或禁用该字段没有任何影响。
更新:我尝试按照@DKidwell 的建议将 formGroup 绑定添加到我的自定义组件,但我仍然收到相同的警告It looks like you're using the disabled attribute...
。我使用 FormBuilder 添加了 formGroup 以更紧密地匹配 Angular Material 示例。
更新 2:我找到的解决方案是创建一个自定义指令,并根据@DKidwell 的回答添加 FormGroup 绑定。我创建的自定义指令基于这篇文章:https ://netbasal.com/disabling-form-controls-when-working-with-reactive-forms-in-angular-549dd7b42110
我像这样实现了自定义指令并删除了 [disabled] 装饰器:
<custom-slide-toggle
[toggleClass]="'enable_user'"
[value]="userFormGroup.get('activeUser').value"
formControlName="activeUser"
[toggleText]="'enable user'"
(selectionChange)="statusChange()"
[isChecked]="userFormGroup.get('activeUser').value"
[required]="false"
[disableControl]="isEditable"
></custom-slide-toggle>
这是我的自定义组件打字稿:
@Component({
selector: 'custom-slide-toggle',
templateUrl: './custom-slide-toggle.component.html',
styleUrls: ['./custom-slide-toggle.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => CustomSlideToggleComponent)
},
{
provide: MatFormFieldControl,
useExisting: CustomSlideToggleComponent
}
],
host: {
'[id]': 'id'
},
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomSlideToggleComponent implements OnInit, OnDestroy, DoCheck, ControlValueAccessor, MatFormFieldControl<boolean> {
private static nextId = 0;
private _placeholder: string;
private _disabled = false;
private _required = false;
private _readlonly = false;
public stateChanges = new Subject<void>();
public errorState = false;
public focused = false;
public ngControl: NgControl;
public toggleFormGroup: FormGroup;
@HostBinding() public id = `custom-slide-toggle-${CustomSlideToggleComponent.nextId++}`;
@HostBinding('class.floating')
get shouldLabelFloat() {
return this.focused || !this.empty;
}
@HostBinding('attr.aria-describedby') describedBy = '';
setDescribedByIds(ids: string[]) {
this.describedBy = ids.join(' ');
}
@Input() public toolTip: string = '';
@Input() public isChecked: boolean;
@Input() public toggleText: string = '';
@Input() public tabNumber: number = null;
@Input() public toggleId: string = '';
@Input() public toggleClass: string;
@Input()
public get disabled(): boolean {
return this._disabled;
}
public set disabled(value: boolean) {
console.log('set disabled trigged');
this._disabled = coerceBooleanProperty(value);
this._disabled ? this.toggleFormGroup.disable() : this.toggleFormGroup.enable();
this.stateChanges.next();
}
@Input()
public get required() {
return this._required;
}
public set required(req: boolean) {
this._required = coerceBooleanProperty(req);
this.stateChanges.next();
}
@Input()
public get readonly(): boolean {
return this._readlonly;
}
public set readonly(value: boolean) {
this._readlonly = coerceBooleanProperty(value);
this._readlonly ?
this.toggleFormGroup.get('toggleFormControl').disable() :
this.toggleFormGroup.get('toggleFormControl').enable();
this.stateChanges.next();
}
@Input()
public get value(): boolean {
let n = this.toggleFormGroup.value;
if (n.toggleFormControl !== null){
return n.toggleFormControl.value;
}
return null;
}
public set value(val: boolean) {
this.toggleFormGroup.setValue({toggleFormControl: val});
this.stateChanges.next();
this.onTouched();
}
@Input()
public get placeholder(): string {
return this._placeholder;
}
public set placeholder(value: string) {
this._placeholder = value;
this.stateChanges.next();
}
@Output() selectionChange: EventEmitter<boolean> = new EventEmitter<boolean>();
public constructor(private injector: Injector, fb: FormBuilder) {
this.toggleFormGroup = fb.group({
'toggleFormControl': ''
});
}
ngOnInit(): void {
this.ngControl = this.injector.get(NgControl);
if (this.ngControl != null) { this.ngControl.valueAccessor = this; }
}
ngOnDestroy(): void {
this.stateChanges.complete();
}
ngDoCheck(): void {
if(this.ngControl) {
this.errorState = this.ngControl.invalid && this.ngControl.touched;
this.stateChanges.next();
}
}
public toggleClick($event: MatSlideToggleChange) {
this.onChange($event.checked);
this.selectionChange.emit($event.checked);
}
public onChanged = (val: boolean) => {};
public onTouched = () => {};
writeValue(value: any) {
console.log('writeValue triggered, incoming value is: ' + value);
if (value !== this.inputControl.value) {
this.inputControl.setValue(value);
this.onChanged(value);
this.stateChanges.next();
}
}
get empty() {
if (this.inputControl?.pristine || this.inputControl?.untouched) return true;
else return false;
}
onBlur() {
this.onTouched();
}
onChange(val: boolean) {
this.writeValue(val);
}
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public registerOnTouched(fn: any): void {
this.onTouched = fn;
}
public setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
这是我的自定义组件的 html:
<mat-slide-toggle
[formControl]="inputControl"
[id]="toggleId"
[class]="toggleClass"
color="primary"
labelPosition="after"
[checked]="isChecked"
[disabled]="disabled"
[required]="required"
(change)="toggleClick($event)"
[tabIndex]="tabNumber"
[matTooltip]="toolTip"
>{{toggleText}}</mat-slide-toggle>
如何在不收到警告的情况下动态禁用我的自定义组件?
解决方案
您需要将 formGroup 绑定添加到您的自定义组件,
<div [formGroup]="yourFormGroup">
<mat-slide-toggle ...>
{{toggleText}}
</mat-slide-toggle>
</div>
您还需要在组件中定义该 formGroup,
FormGroup yourFormGroup = new FormGroup({
inputControl: new FormControl()
});
一旦设置正确,您就不需要绑定到自定义控件模板中的 [disabled] 属性。
推荐阅读
- apache-kafka - 为 confluent kafka-connect-s3 实现自定义 AvroConverter
- javascript - 如何检测是否在新的 Windows 终端中运行?
- sql - Oracle:如何在函数中包装游标?
- php - 调用“in_array”似乎不起作用
- fortran - Fortran 如何处理可选参数和字符串?
- machine-learning - 如何使用在数据集上训练的 SVC ML 模型预测新患者的结果
- jquery - 使用 mindmup / editable-table 更改表格时如何获取单元格名称和行 ID
- django - 如何默认激活所有管理命令的翻译?
- java - 在java中的链接哈希图中查找特定键的值
- javascript - 不同环境下的 Babel 和 Lerna 设置问题