Home > Software engineering >  Create common input field in Angular
Create common input field in Angular

Time:01-21

I have created common input field which can be usable across app and it will work with or without reactive form.

For e.g.: I have created common input angular component but it works with reactive form only as it has formGroup and formControlName.

input.html:

    <div  *ngIf="isRequired" [formGroup]="parentForm">
      <label >
        {{labelText}}
      </label>
      <input [type]="inputType"   [control]="control" [formControlName]="formControlNameText" [placeholder]="placeholderText">
    </div>

input.ts:

    import { Component, OnInit, Input } from '@angular/core';
    
    @Component({
      selector: 'app-input',
      templateUrl: './input.component.html',
      styleUrls: ['./input.component.scss'],
    })
    export class InputComponent implements OnInit {
    
      @Input() parentForm: any;
      @Input() labelText: string;
      @Input() inputType: string = "text";
      @Input() formControlNameText: string;
      @Input() placeholderText: string;
      @Input() isRequired: boolean = false;
      @Input() requiredMsg: string;
      @Input() maxlengthMsg: string;
      @Input() control: any;
      @Input() type: string;
    
      constructor() { }
    
      ngOnInit() { }
    
    }

Call from one of my form Page:

<app-input parentForm="surveyResponseForm" labelText="test" inputType="text" placeholderText="placeholder"  
    formControlNameText="authorName"  control="" isRequired=true id="authorName">
</app-input>

How do I use this common input if I want to use this without form? I mean how do I use this selector: app-input in a component which doesn't have any form.

CodePudding user response:

You could add an @Input() property to your component, for example useInForm: boolean, and check its value in your template. If useInForm is true, you would use the [formGroup] and formControlName properties, otherwise you would use a regular element without those properties example in the withoutFormTemplate.

<div  *ngIf="isRequired && useInForm; else withoutFormTemplate" [formGroup]="parentForm">
  <label >
    {{labelText}}
  </label>
  <input [type]="inputType"   [control]="control" [formControlName]="formControlNameText" [placeholder]="placeholderText">
</div>

<ng-template #withoutFormTemplate>
    <input [(ngModel)]="control" [type]="inputType"  [placeholder]="placeholderText">
<ng-template>

CodePudding user response:

You solve it by creating a FormGroup. It's not easiest solution, but that working on multiple scenarios. Or maybe give you some clues how to solve your problem...

Form component ts

// Reactive Forms
form: FormGroup;    

constructor(private formBuilder: FormBuilder) { }

ngOnInit() {
  // Form structure and validators
  this.form = this.formBuilder.group({
    'user' : this.formBuilder.group({
      'username' : ['', Validators.required],
      'email' : ['', [Validators.required, Validators.email]]
    }),
    'identity' : this.formBuilder.group({
      'firstname' : ['', Validators.required],
      'lastname'  : ['', Validators.required],
      'address' : this.formBuilder.group({
        'street' : ['', Validators.required],
        'city'  : ['', Validators.required],
      })
    })
  });        
}

onSubmit() {
    // Get object with same structure as form but only with values
    console.log(this.form.value);
    alert('Form is '   (this.form.invalid ? 'invalid' : 'valid'));
}

Form component html

<form [formGroup]="form" (ngSubmit)="onSubmit()">
    <form-text [formGroupParent]="form.get(['user'])"
               [formGroupControlName]="'username'">
    </form-text>
    <form-text [formGroupParent]="form.get(['user'])"
               [formGroupControlName]="'email'">
    </form-text>
    <hr>
    <form-text [formGroupParent]="form.get(['identity'])"
               [formGroupControlName]="'firstname'">
    </form-text>
    <form-text [formGroupParent]="form.get(['identity'])"
               [formGroupControlName]="'lastname'">
    </form-text>
    <hr>
    <form-text [formGroupParent]="form.get(['identity','address'])"
               [formGroupControlName]="'street'">
    </form-text>
    <form-text [formGroupParent]="form.get(['identity','address'])"
               [formGroupControlName]="'city'">
    </form-text>
    <button type="submit">Submit</button>
</form>

Custom input component ts (form-text)

// Needed to bind formControlName
@Input() formGroupParent: FormGroup;
@Input() formGroupControlName: string;
// FormControl store validators
control: FormControl;

ngOnInit() {
    // Fetch Form control (validator) from FormGroup parent
    this.control = <FormControl>this.formGroupParent.get(this.formGroupControlName);
}

Custom input component html (form-text)

<ng-container [formGroup]="formGroupParent">
  <label>{{formGroupControlName}}</label> 
  <input type="text" formControlName="{{formGroupControlName}}">
</ng-container

Blockquote

  • Related