How to make generic component with form control input for Angular Forms in app

北慕城南 提交于 2021-01-27 20:08:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!