问题
I have a reactive form. The setup is similar to this:
myForm: FormGroup;
this.myForm= new FormGroup({
name: new FormControl("", [Validators.required, Validators.maxLength(15), Validators.pattern('...')]),
...
});
I use this on my form like this:
<input
type="text"
formControlName="name"
/>
<div *ngIf="name.errors?.required">
Name is required
</div>
<div *ngIf="name.errors?.maxlength">
Name must be {{ name.errors.maxlength.requiredLength }} characters
</div>
<div *ngIf="name.errors?.pattern">
Name has invalid characters.
</div>
This is just a cut down version of my form. I have multiple input and I've had to create the error div's for each input.
So to fix this I've tried to create a component. The component is very similar to the code above:
<input
type="text"
[formControlName]="formControlName"
/>
<div *ngIf="name.errors?.required">
Name is required
</div>
etc...
ts file:
@Component({
selector: 'app-text',
templateUrl: './text.component.html'
})
export class TextComponent {
@Input() formControlName: FormControl;
}
So on my form I'd like to use this component as follows:
<app-text [formControlName]="name"></app-text>
But I can't get this to work with the formControlName property.
Is this possible?
Thanks
I'm nearly there.
I've create this StackBlitz so show my progress:
Demo
Just struggling with the errors now and how to access the formControl to check for those errors
回答1:
If you want access to the formControl
the best thing to use is NgControl
as a DI
Reasoning:
NgModel
FormControlDirective
FormControlName
Are all sub-classes of NgControl
so you will be doing yourself a great deal of help if you did it this way so that if down the line you change your mind about using formControl to NgControl etc... you will have already covered those bases by using NgControl
So by example it would look something like
import { Component, OnInit, Self } from '@angular/core';
import { NgControl } from '@angular/forms';
@Component({
selector: 'app-text',
templateUrl: './text-box.component.html',
styleUrls: ['./text-box.component.css']
})
export class TextBoxComponent implements OnInit {
constructor(@Self() private ngControl: NgControl) { }
ngOnInit() {
console.log(this.ngControl);
}
}
Html
<app-text[formControl]="control"></app-text>
The reason we use @Self is so that the component does not look further up the injector tree to find a ngControl
but only on it's element. So you can nest etc...
This is very beneficial to directives as well but so far i hope this helped!
回答2:
You need to pass the form control to the input element ,
<input
[value]="val"
type="text"
(input)="val=$event.target.value;onChange($event.target.value)"
(blur)="onTouched()"
[formControl]="control"
>
<span *ngIf="control && !control.valid && control.touched">
<span class="error" *ngIf="control.errors['required']"> The field should not be empty</span>
<span class="error" *ngIf="control.errors['email']"> The field should be an email
</span>
</span>
Get the control in your custom component as input and show the error based on this.
import { Component, OnInit, forwardRef, Input, OnChanges } from '@angular/core';
import { FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TestComponent), multi: true }
]
})
export class TestComponent implements ControlValueAccessor, OnChanges {
constructor() { }
propagateChange:any = () => {};
@Input() control: FormControl;
@Input('messageValue') _messageValue = 'whateves';
get messageValue() {
return this._messageValue;
}
set messageValue(val) {
console.log('set messageValue', val)
this._messageValue = val;
this.propagateChange(val);
}
hi(event) {
console.log('hi');
console.log(event)
this.messageValue = event;
}
ngOnInit() {
}
ngOnChanges(changes) {
console.log('changes', changes);
this.propagateChange(this.messageValue);
}
writeValue(value) {
console.log('writeValue', value);
if (value) {
this.messageValue = value;
}
}
registerOnChange(fn) {
console.log('onChange')
this.propagateChange = fn;
}
registerOnTouched() {}
}
来源:https://stackoverflow.com/questions/56580902/passing-formcontrolname-into-angular-component