反应式表单组件
Reactive Form Components
我们使用了很多 Angular material 字段,它们的呈现方式都是一样的。我想要一种方法来简化来自 UI 设计人员和以后维护的任何更改。
我如何创建一个组件来减少 HTML 的这个块(只是示例代码)
<div fxFlex>
<mat-form-field>
<mat-label>The Label</mat-label>
<input matInput formControlName="controlName" ... >
<mat-hint>*Required</mat-hint>
<mat-error *ngIf="controlName.invalid && controlName.touched">{{errorMessage}}</mat-error>
</mat-form-field>
<div>
归结到像这样明智的事情
<custominput formControlName="controlName" [errorMessage]="Error" ...></custominput>
我尝试按照这些教程进行操作,但没有成功。
Angular material Custom Fields
我真的不明白如何从本质上应用到输入字段。
这是我目前剩下的。
TS 文件内容
import { Component, ChangeDetectionStrategy, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatInput } from '@angular/material/input';
@Component({
selector: 'hr-textinput',
template:`
<div [ngClass]="labelPosition">
<mat-label>{{label}}</mat-label>
<mat-form-field>
<input #inputFieldIdentifier matInput formControlName={{controlName}} id={{id}} (blur)="onTouched()">
<mat-error *ngIf="controlName.invalid">{{errorMsg}}</mat-error>
<mat-hint *ngIf="mandatory">*Required</mat-hint>
</mat-form-field>
</div>
`,
styleUrls: ['./textinput.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi:true,
useExisting: TextinputComponent
}
]
})
export class TextinputComponent implements ControlValueAccessor, OnInit {
@ViewChild('inputFieldIdentifier') inputField: MatInput;
@Input() controlName: string = "";
@Input() mandatory: boolean = false;
@Input() label: string = "";
@Input() errorMsg = "";
@Input() labelPosition: string = "before"; // "before" and "above" are the two options available at present
@Input() id: string = "";
touched = false;
disabled = false;
constructor() {
}
ngOnInit(): void {
this.id = `${this.controlName}_ID`;
}
onChange = (value) => {};
onTouched = () => {};
writeValue(fieldValue: any): void {
this.inputField.value = fieldValue;
}
registerOnChange(onChangeFn: any): void {
this.onChange = onChangeFn;
}
registerOnTouched(onTouchedFn: any): void {
this.onTouched = onTouchedFn;
}
setDisabledState?(isDisabled: boolean): void {
this.inputField.disabled = isDisabled;
}
markAsTouched() {
if (!this.touched) {
this.onTouched();
this.touched = true;
}
}
}
SCSS 文件内容
.above {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: left;
.mat-form-field {
padding-top: 6px;
}
}
.before {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.mat-form-field {
padding-left: 12px;
}
}
非常感谢任何想法,因为我显然不知道。
您看到 The app cannot find my 'form'
错误的原因是因为您在本应实现 formControlName
接口的组件中使用了 formControlName
指令。如果您从自定义输入组件模板中删除 formControlName
指令,您将不会再看到该错误。
换句话说,在实现 ControlValueAccessor
时,您实际上是在告诉 Angular 您的组件知道如何使用 formControlName
指令,因此 formControlName
指令应该是实例化时放置您的自定义组件。即
<hr-textinput formControlName="myField">
</hr-textinput>
我分叉了你的 stackblitz 以显示工作形式:https://stackblitz.com/edit/angular-ivy-onycez?
我们使用了很多 Angular material 字段,它们的呈现方式都是一样的。我想要一种方法来简化来自 UI 设计人员和以后维护的任何更改。
我如何创建一个组件来减少 HTML 的这个块(只是示例代码)
<div fxFlex>
<mat-form-field>
<mat-label>The Label</mat-label>
<input matInput formControlName="controlName" ... >
<mat-hint>*Required</mat-hint>
<mat-error *ngIf="controlName.invalid && controlName.touched">{{errorMessage}}</mat-error>
</mat-form-field>
<div>
归结到像这样明智的事情
<custominput formControlName="controlName" [errorMessage]="Error" ...></custominput>
我尝试按照这些教程进行操作,但没有成功。
Angular material Custom Fields
我真的不明白如何从本质上应用到输入字段。 这是我目前剩下的。
TS 文件内容
import { Component, ChangeDetectionStrategy, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatInput } from '@angular/material/input';
@Component({
selector: 'hr-textinput',
template:`
<div [ngClass]="labelPosition">
<mat-label>{{label}}</mat-label>
<mat-form-field>
<input #inputFieldIdentifier matInput formControlName={{controlName}} id={{id}} (blur)="onTouched()">
<mat-error *ngIf="controlName.invalid">{{errorMsg}}</mat-error>
<mat-hint *ngIf="mandatory">*Required</mat-hint>
</mat-form-field>
</div>
`,
styleUrls: ['./textinput.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi:true,
useExisting: TextinputComponent
}
]
})
export class TextinputComponent implements ControlValueAccessor, OnInit {
@ViewChild('inputFieldIdentifier') inputField: MatInput;
@Input() controlName: string = "";
@Input() mandatory: boolean = false;
@Input() label: string = "";
@Input() errorMsg = "";
@Input() labelPosition: string = "before"; // "before" and "above" are the two options available at present
@Input() id: string = "";
touched = false;
disabled = false;
constructor() {
}
ngOnInit(): void {
this.id = `${this.controlName}_ID`;
}
onChange = (value) => {};
onTouched = () => {};
writeValue(fieldValue: any): void {
this.inputField.value = fieldValue;
}
registerOnChange(onChangeFn: any): void {
this.onChange = onChangeFn;
}
registerOnTouched(onTouchedFn: any): void {
this.onTouched = onTouchedFn;
}
setDisabledState?(isDisabled: boolean): void {
this.inputField.disabled = isDisabled;
}
markAsTouched() {
if (!this.touched) {
this.onTouched();
this.touched = true;
}
}
}
SCSS 文件内容
.above {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: left;
.mat-form-field {
padding-top: 6px;
}
}
.before {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.mat-form-field {
padding-left: 12px;
}
}
非常感谢任何想法,因为我显然不知道。
您看到 The app cannot find my 'form'
错误的原因是因为您在本应实现 formControlName
接口的组件中使用了 formControlName
指令。如果您从自定义输入组件模板中删除 formControlName
指令,您将不会再看到该错误。
换句话说,在实现 ControlValueAccessor
时,您实际上是在告诉 Angular 您的组件知道如何使用 formControlName
指令,因此 formControlName
指令应该是实例化时放置您的自定义组件。即
<hr-textinput formControlName="myField">
</hr-textinput>
我分叉了你的 stackblitz 以显示工作形式:https://stackblitz.com/edit/angular-ivy-onycez?