3

I'm trying to create a custom Input component using Reative Form in Angular 7 but i'm having trouble passing events to the input field.

My component has a label and an input field and a specific layout. My component html looks like this:

<div id="customInputGroup"  [formGroup]="parentFormGroup" [ngClass]="{'input-value': hasValue()}">
    <label [for]="inputId">{{label}}</label>
    <input [id]="inputId"  [name]="inputName"  class="form-control" [placeholder]="placeholder" [formControlName]="inputName" [mask]="mask">
</div>

And in my Component:

@Component({
  selector: 'app-input-field',
  templateUrl: './input-field.component.html',
  styleUrls: ['./input-field.component.css']
})
export class InputFieldComponent implements OnInit {


  @Input('placeholder') placeholder = '' ;
  @Input('label') label = '';
  @Input('inputId') inputId = '';
  @Input('inputName') inputName = '';
  @Input('parentFormGroup') parentFormGroup:FormGroup;
  @Input('mask') mask;
  constructor() { }

  ngOnInit() {
  }

  hasValue(){
    return (this.parentFormGroup.get(this.inputName).value != undefined 
    && this.parentFormGroup.get(this.inputName).value != null 
    && this.parentFormGroup.get(this.inputName).value != '')
  }

Everything was working fine till i had to handle an input onBlur event(or it could be any other input event). The result i want is to call my component passing any event like this:

<app-input-field (blur)="functionName()"></app-input-field>

or

<app-input-field (keyup)="functionName()"></app-input-field>

And my component will be able to pass these events to my input field 'dynamically'. Is it possible to do it?

Mateus Borges
  • 53
  • 1
  • 6

2 Answers2

5

Events like blur works on input field , not selectors like <app-input-field>

You can emit event for all events like blur, keyup, mouseover etc..

InputFieldComponent:

HTML:

<input (blur)="functionName('blur')" (keyup)="functionName('keyUp')" [id]="inputId"  [name]="inputName"  class="form-control" [placeholder]="placeholder" [formControlName]="inputName" [mask]="mask">

TS:

@Output() OnInputEvent= new EventEmitter();

functionName(eventName) {
    this.OnInputEvent.emit(eventName);
}

In your component:

<app-input-field (OnInputEvent)="functionName($event)"></app-input-field>

TS:

functionName(event) {
    switch (event) {
       case "blur":
       ...
       break;

       case "keyUp":
       ...
       break;
    }
}

Working Demo

Adrita Sharma
  • 21,581
  • 10
  • 69
  • 79
  • you did a good job @Adrita ,for keyup event you don't need to do anything it will bubble and you can catch it on the element itself but blur not , check my answer ☕ – Muhammed Albarmavi Sep 16 '19 at 14:44
  • Thanks @malbarmawi , your solution is also great. But I just think that by emitting all the events from output, they can be handled in the same place – Adrita Sharma Sep 16 '19 at 16:07
  • both of ours answer are correct and can combine both together , I do like the idea of compose all event in single event , up – Muhammed Albarmavi Sep 17 '19 at 07:18
  • but if the component gone to use as wrapper for input element and will be use in reactive form he must implement ControlValueAccessor , I think – Muhammed Albarmavi Sep 17 '19 at 07:22
  • @malbarmawi Yeah... We are discussing it ourselves but the one who asked the question haven't used any of the answer I guess :D By the way thank you, it's not everyday somebody who has an answer appreciating another answer – Adrita Sharma Sep 17 '19 at 07:23
  • 1
    Yeah I have read about `ControlValueAccessor` but never really used it, may be you can add an answer using it, I would get to learn about it – Adrita Sharma Sep 17 '19 at 07:27
4

for blur event you need to create a eventemitter with the same name and emit this event on input elemnt blur emit

export class InputFieldComponent implements OnInit {

  @Output() blur:EventEmitter<any> = new EventEmitter(); // 

  constructor() { }

  ngOnInit() {
  }

}

template

<input type="text" (blur)="blur.emit($event)"  >

app.template

<app-input-field (blur)="onBlur($event)" (keyup)="onKeyup($event)"></app-input-field>

we did this for the blur event because the event is not bubble where the keyup will work without create any custom event because it bubble.

demo

you can implement two way data binding like this

  @Input() value:EventEmitter<any> = new EventEmitter();

  @Output() valueChange:EventEmitter<any> = new EventEmitter();

template

<app-input-field  [(value)]="name" ></app-input-field>

demo

any bubble event like input,keypress,keyup,keydown you can capture on the element itself or you can work around it like what we did on blur event.

Muhammed Albarmavi
  • 23,240
  • 8
  • 66
  • 91