问题
I've created component for datepicker that I want to use in many other components in my application. I have some problems becouse it doesn't change value of parent form group control.
Lets get to the code:
export class DatePickerComponent {
@ViewChild('input', {read: ElementRef, static: false}) inputRef: ElementRef;
@Input()
formName?: FormGroup;
@Input()
formControlName: any;
constructor() {
this.formControlName.setValue(['']);
}
onKeyPress = (event) => {
const pressedKey = event.keyCode;
if (
pressedKey !== 8 &&
pressedKey !== 9 &&
pressedKey !== 13 &&
((pressedKey < 48 || pressedKey > 105) || (pressedKey > 57 && pressedKey < 96))
) {
event.preventDefault();
}
}
onKeyUp = (event) => {
const pressedKey = event.keyCode;
const inputString: string = this.formControlName.value;
if (!inputString) {
return;
}
if (inputString.length === 11) {
this.inputRef.nativeElement.value = inputString.slice(0, -1);
return;
}
if (pressedKey === 8 && (inputString.length === 3 || inputString.length === 6)) {
const newValue = inputString.slice(0, -1);
this.formControlName.setValue(newValue);
this.inputRef.nativeElement.value = newValue;
} else if (inputString.length === 2 || inputString.length === 5) {
const newValue = inputString + '/';
this.formControlName.setValue(newValue);
this.inputRef.nativeElement.value = newValue;
}
}
}
And the template:
<div [formGroup]="formName">
<input
class="form-control"
formControlName="{{formControlName}}"
placeholder="DD/MM/YYYY"
name="dp"
ngbDatepicker
#d="ngbDatepicker"
[minDate]="{year: 1930, month: 1, day: 1}"
(click)="d.toggle()"
(keydown)="onKeyPress($event)"
(keyup)="onKeyUp($event)">
</div>
So I wanted to use it in parent component that is form with FormGroup
property set to X. To use my component I've added
<app-date-picker [formControlName]="birthDate" [formName]="registerForm"></app-date-picker>
Maybe I did something wrong in parent component:
export class UserFormComponent implements OnInit {
@Input() isRegisterPage: boolean;
@Input() isProfilePage: boolean;
@Input() user: UserInfo;
registerForm: FormGroup;
birthDate: FormControl;
loading: boolean;
.e
.t
.c
How to make my datepicker reusable correctly? Maybe somone can help me?
Fiddle with only datepicker (not used in parent form): https://stackblitz.com/edit/angular-i47zuz-jj5glk?file=app/datepicker-popup.ts
回答1:
you are doing it wrong !, to make your custom component work with forms as FormControl
you should make it FormControl
, to do so, you need to implement ControlValueAccessor
interface, so your component would work as custom FormControl
, you can read how to do it here -> ControlValueAccessor, if you have problems on implementing it let me know, I can provide further help, but try to implement it on your own first, to learn better
回答2:
Really you need't make a custom form Control, it's only pass the control as input
In parent, e.g.
<form [formGroup]="form">
<my-component [control]="form.get('bithdate')"></my-component>
</form>
You component
<input [formControl]="control" ...>
@Input() control:FormControl
回答3:
You can take a look at a library I wrote for building forms called Easy Angular. https://github.com/adriandavidbrand/ngx-ez it allows you to build self validating forms with very little code and extending the controls to make your own is easy.
Here is a BootStrap date picker implemented in it.
import { Component, Optional, Self } from '@angular/core';
import { NgControl } from '@angular/forms';
import {
EzControlBase,
EzFormDirective,
EzFormConfigService,
EzFormConfigDirective,
EzFormReadonlyDirective
} from 'ngx-ez';
@Component({
selector: 'ez-date',
templateUrl: './ez-date.component.html',
styleUrls: ['./ez-date.component.css'],
providers: [{ provide: EzControlBase, useExisting: EzDateComponent }]
})
export class EzDateComponent extends EzControlBase {
constructor(
configService: EzFormConfigService,
@Optional() configDirective: EzFormConfigDirective,
@Optional() ezForm: EzFormDirective,
@Optional() ezezReadonly: EzFormReadonlyDirective,
@Self() @Optional() ngControl: NgControl
) {
super(configService, configDirective, ezForm, ezezReadonly, ngControl);
}
}
and the template
<ez-control>
<ng-content></ng-content>
<ng-container controls-container>
<ng-container *ngIf="readonly$ | async">{{ value | date : 'dd/MM/yyyy' }}</ng-container>
<input bsDatepicker [bsConfig]="{ dateInputFormat: 'DD/MM/YYYY' }" [id]="(name$ | async) + '_control_input'" [attr.aria-describedby]="(valid$ | async) ? null : (name$ | async) + '_validation_message'" [attr.maxlength]="maxlength$ | async" type="text" [attr.placeholder]="placeholder$ | async" [value]="value | date : 'dd/MM/yyyy'" (bsValueChange)="onChange($event)"
[ngClass]="(config$ | async).inputClasses" [valid]="valid$ | async" [class.d-none]="readonly$ | async">
</ng-container>
</ez-control>
See a working demo at this StackBlitz https://stackblitz.com/edit/angular-t1wshi?file=src%2Fapp%2Fez-date%2Fez-date.component.html
来源:https://stackoverflow.com/questions/58466582/how-to-make-generic-component-with-form-control-input-for-angular-forms-in-app