我在 Angular 10 应用程序中遇到问题,在初始化时将 formGroup 的状态传播到其父级。
问题:在组件初始化时,子表单的验证状态未正确传播到多个级别的父级中。
更准确地说,我有 3 个嵌套组件。它们都是表单,并且两个子级都实现 ControlValueAccessor。它们通过“formControlName”属性进行通信。最深的形式初始化错误(必填字段)。父级不会收到有效性状态(它仍然有效)。
这是问题的重现:
https://stackblitz.com/edit/ngx-sub-form-hzo8wj?file=src/app/app.component.ts
我希望“基本表单组”在初始化时无效。“级别 2”的有效性应在“基本表单组”中的“级别 1”然后“级别 1”中传播。
它可能来自正常的角度周期。
我在等待更好的解决方案时发现了一个 hack:
public ngAfterViewInit(): void {
this._injector.get(NgControl).control.updateValueAndValidity();
}
Run Code Online (Sandbox Code Playgroud)
在第一个角度周期后,我们手动重新启动子级对父级的验证。这是级联在所有子组件中的。
我怎样才能避免使用这个黑客?
我正在创建一个实现 ControlValueAccessor 的组件以在反应式表单中使用,它只是一个输入元素的包装器,上面有一些管道。
我已经注入了 NgControl 以检索有效/无效状态并将它们传播到内部输入元素。
当在另一个输入中找到输入值时,它是无效的。
在 Stackblitz 上工作正常,但是当我进行ng build --prod 时,它会引发错误:
错误:NgControl 没有提供程序(“[ERROR ->])
你看到任何问题吗?
谢谢!
<mat-error>在子 ControlValueAccessor 组件中没有父formControl验证的影响。
<!-- Parent component template -->
<app-unique-name-text-box [formControl]="categoryName"></app-unique-name-text-box>
Run Code Online (Sandbox Code Playgroud)
// Parent Component ts
this.addCategoryForm = fb.group({
'categoryName': ['', Validators.compose([Validators.required, BlankSpaceValidator.validate])]
});
this.categoryName = this.addCategoryForm.controls['categoryName'];
Run Code Online (Sandbox Code Playgroud)
<!-- Child component template -->
<mat-form-field class="example-full-width">
<input matInput placeholder="Name" [formControl]="uniqueNameControl" (blur)="onInputBlur()">
<mat-error *ngIf="errorState">Enter a unique name</mat-error>
</mat-form-field>
Run Code Online (Sandbox Code Playgroud)
// Child component ts
import {Component, OnInit, Optional, Self} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, NgControl} from '@angular/forms';
import {distinctUntilChanged} from "rxjs/operators";
@Component({
selector: 'app-unique-name-text-box',
templateUrl: './unique-name-text-box.component.html',
styleUrls: ['./unique-name-text-box.component.scss']
})
export class UniqueNameTextBoxComponent implements …Run Code Online (Sandbox Code Playgroud) 这是简单的自定义表单控件
@Component({
selector: 'app-custom-control',
template: `
{{ value }}
<input [ngModel]="value" (ngModelChange)="onChange($event)">
`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomControlComponent),
multi: true,
}]
})
export class CustomControlComponent implements ControlValueAccessor {
private value: any;
private onChange: (val) => void;
private onTouch: () => void;
writeValue(value: any) {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
}
Run Code Online (Sandbox Code Playgroud)
使用如下:
@Component({
selector: 'my-app',
template: `
<app-custom-control
[ngModel]="model"
(ngModelChange)="onChange($event)">
</app-custom-control>
<input [ngModel]="model" …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Angulars ControlValueAccessor 创建自定义元素。目标是具有三种状态的开关:真、假和空。默认情况下应选择 Null,我尝试了其他帖子中的一些解决方案,但它们不起作用。
我尝试在 mat-button-toggle-group 中添加“value=null”,并在 null mat-button-toggle 本身中添加“checked”属性。
HTML:
<div class="nullableBoolWrapper" fxLayout="row">
<mat-label class="centred-vertically">{{ label }}</mat-label>
<mat-button-toggle-group class="selection-button"
[disabled]="isDisabled"
[(ngModel)]="selectedValue"
(change)="changed($event)">
<mat-button-toggle ngDefaultControl value=true>{{ descriptionList[0].description }}</mat-button-toggle>
<mat-button-toggle ngDefaultControl value=false>{{ descriptionList[1].description }}</mat-button-toggle>
<mat-button-toggle ngDefaultControl value=null [disabled]="!selectableNull">{{ descriptionList[2].description }}</mat-button-toggle>
</mat-button-toggle-group>
Run Code Online (Sandbox Code Playgroud)
TS:
import { Description } from './../core/models/description';
import { Component, ViewEncapsulation, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export const NULLABLE_BOOL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NullableBoolComponent),
multi: true
}; …Run Code Online (Sandbox Code Playgroud) 我按照本指南创建ControlContainer可重用表单,成功创建了可重用表单组,但是当我尝试使用 创建可重用表单元素时matInput,遇到了No value accessor错误。这是my-form-field.ts文件:
import { Component, Input, OnInit } from '@angular/core';
import {
ControlContainer,
FormBuilder, FormControl,
FormGroup,
FormGroupDirective,
} from '@angular/forms';
@Component({
selector: 'my-form-field',
template: `
<mat-form-field>
<mat-label>{{label}}</mat-label>
<input matInput [formControlName]="formControlName">
</mat-form-field>
`,
viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
})
export class MyFormFieldComponent implements OnInit {
@Input() formControlName: string;
@Input() label: string;
formGroup: FormGroup;
constructor(private ctrlContainer: FormGroupDirective, private formBuilder: FormBuilder) {
}
ngOnInit(): void {
this.formGroup = this.ctrlContainer.form; …Run Code Online (Sandbox Code Playgroud) code-reuse angular-material angular angular-reactive-forms controlvalueaccessor
我有一个根据本文制作的自定义输入:medium.com:dont-reinvent-the-wheel。
\n这是我的代码,它处于严格模式 \xe2\x96\xbc
\n// input.component.ts\n\nimport { Component, Input, ViewChild } from \'@angular/core\';\nimport {\n ControlContainer,\n ControlValueAccessor,\n FormControl,\n FormControlDirective,\n NG_VALUE_ACCESSOR\n} from \'@angular/forms\';\nimport {\n FloatLabelType,\n MatFormFieldAppearance\n} from \'@angular/material/form-field\';\n\n@Component({\n selector: \'app-input\',\n templateUrl: \'./input.component.html\',\n styleUrls: [\'./input.component.scss\'],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: InputComponent,\n multi: true\n }\n ]\n})\nexport class InputComponent implements ControlValueAccessor {\n isDisabled!: boolean;\n\n @Input() isRequired!: boolean;\n\n @Input() label!: string;\n\n @Input() placeholder!: string;\n\n @Input() readonly!: boolean;\n\n @Input() appearance: MatFormFieldAppearance = \'fill\';\n\n @Input() floatLabel: FloatLabelType = \'auto\';\n\n @ViewChild(FormControlDirective, { static: true })\n …Run Code Online (Sandbox Code Playgroud) angular angular-reactive-forms controlvalueaccessor angular-controlvalueaccessor
我试图使用CVA具有2个嵌套表单。问题是当我将第二个from绑定到formControl时没有用数据初始化。
我有主表格:
this.requestForm = this.fb.group({
garageId: 0,
routes: new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl,
regionName: new FormControl,
municipalityName: new FormControl,
settlementName: new FormControl,
description: new FormControl,
})
]),
endDateTime: 0,
});
Run Code Online (Sandbox Code Playgroud)
在主要形式的html中,我使用formArrayName将路由绑定到。
<app-cva-form-array formArrayName="routes"></app-cva-form-array>
Run Code Online (Sandbox Code Playgroud)
组件CVA-FORM-ARRAY具有。
form = new FormArray([
new FormGroup({
addressPointId: new FormControl,
municipalityId: new FormControl,
regionId: new FormControl,
rvId: new FormControl,
sequenceNumber: new FormControl,
settlementId: new FormControl, …Run Code Online (Sandbox Code Playgroud) typescript angular angular-reactive-forms controlvalueaccessor
angular ×8
angular-controlvalueaccessor ×1
angular8 ×1
code-reuse ×1
formgroups ×1
typescript ×1