Ang*_*hef 10 angular2-forms angular
我有一个自定义FormFieldComponent,用于封装表单字段的HTML和错误显示逻辑:
@Component({
selector: 'field',
template: `
<div class="form-group">
<label class="control-label">{{label}}</label>
<ng-content></ng-content> <!-- Will display the field -->
<!-- Here, put error display logic -->
</div>
`
})
export class FormFieldComponent {
@Input() label: string; // Field label
@Input() theControl: FormControl; // Current form control, required to display errors
}
Run Code Online (Sandbox Code Playgroud)
在FormFieldComponent,我需要一个FormControl实例来显示错误.
我的表单看起来像这样:
<form [formGroup]="myForm">
...
<field label="Title" [theControl]="myForm.get('title')">
<input type="text" formControlName="title">
</field>
...
</form>
Run Code Online (Sandbox Code Playgroud)
但我对上面的代码并不完全满意.如您所见,我在两个位置指定字段的键:在[theControl]输入属性和formControlName指令中.
如果我能写的话,代码会更简洁:
<field label="Title">
<input type="text" formControlName="title">
</field>
Run Code Online (Sandbox Code Playgroud)
注意[theControl]输入属性是如何消失的.本FieldComponent应该能够拿到FormControl实例包含,但如何保持?
我已经尝试使用@ContentChildren装饰器查询组件的FormControl指令模板,但它不起作用:
export class FormFieldComponent {
@ContentChildren(FormControlDirective) theControl: any;
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是将字段的密钥作为输入传递给FormFieldComponent然后让组件使用该密钥:
formControlName指令应用于它包含的字段.<form>,访问相应的FormGroup实例,并从中提取FormControl实例.你不能.(好吧,也许你可以,但它会是hacky!)
FormControl是不可注射的.指令是可注射的,但是,你将不得不处理formControlName,ngModel,formControl,等,他们将无法从包装组件,但它的儿童使用...
对于你的情况,你可以试试,@ContentChildren(FormControlName) theControl: any;因为FormControlDirective你的代码没有暗示,但你FormControl无论如何都无法访问(属性_control是内部的,所以它将是一个黑客)...
因此,您应该坚持从处理该组件的组件中管理您的错误FormGroup.
但是,如果你想显示一个自定义输入(不会显示错误信息,但能够显示此输入处于错误状态(主机元素将获取ng-valid,ng-invalid类,所以这只是一个风格问题),你可以通过实施来做到这一点ControlValueAccessor.
控件和本机元素之间的桥梁.
ControlValueAccessor抽象化将新值写入表示输入控件的DOM元素的操作.
这意味着实现了这个接口指令/组件可以使用ngModel,formControl等...
例如: <my-component [(ngModel)]="foo"></my-component>
它不是你问题的确切复制品,但是这个实现为我解决了同样的问题:
export const INPUT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true
};
@Component({
selector: "field",
template: `<!--put anything you want in your template-->
<label>{{label}}</label>
<input #input (input)="onChange($event.target.value)" (blur)="onTouched()" type="text">`,
styles: [],
providers: [INPUT_VALUE_ACCESSOR]
})
export class InputComponent implements ControlValueAccessor {
@ViewChild("input")
input: ElementRef;
@Input()
label:string;
onChange = (_: any) => { };
onTouched = () => { };
constructor(private _renderer: Renderer) { }
writeValue(value: any): void {
const normalizedValue = value == null ? "" : value;
this._renderer.setElementProperty(this.input.nativeElement, "value", normalizedValue);
}
registerOnChange(fn: (_: any) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
setDisabledState(isDisabled: boolean): void {
this._renderer.setElementProperty(this.input.nativeElement, "disabled", isDisabled);
}
}
Run Code Online (Sandbox Code Playgroud)
那你就可以:
<field label="Title" formControlName="title"></field>
Run Code Online (Sandbox Code Playgroud)
您可以通过以下方式获得 Form Control Name 实例:
@Component({
selector: 'field',
templateUrl: './field.component.html',
styleUrls: ['./field.component.scss']
})
export class FieldComponent implements AfterContentInit {
@Input()
public label: string;
@ContentChild(FormControlName)
public controlName: FormControlName;
public ngAfterContentInit(): void {
console.log(this.controlName.control);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5006 次 |
| 最近记录: |