angular

in Angular2 how to know when ANY form input field lost focus


In Angular2 how to know when ANY input field has lost focus..! If I use observables on the form:

form.valueChange.subscribe...

wont work since I really want to know when a field lost it's blur (focus) so I can update my store (if I update the store before losing focus, my cursor on a text input gets moved to the end, since the data gets swapped which is weird looking)

of course I can also add (change)="" on each input, but I have a lot of'em...

I was thinking something of the sorts of:

this.form.valueChanges.debounceTime(1000).subscribe((changes:any) => {
  if (this.form.dirty){
    this.appStore.dispatch(this.resellerAction.updateResellerInfo(changes))
  }
});

but the problem is that the dirty remains dirty, so it stuck in an everlasting loop of change detections...

tx

Sean


Solution

  • The blur event doesn't bubble, therefore we need to listen on every input element directly. Angular provides a nice solution for this situation.

    A directive that applies to all input elements inside your template.

    This directive uses a host-listener to listen for the blur events on all elements where the selector applies and forwards a bubbling input-blur event:

    @Directive({
      selector: 'input,select',
      host: {'(blur)': 'onBlur($event)'}
    })
    class BlurForwarder {
      constructor(private elRef:ElementRef, private renderer:Renderer) {}
    
      onBlur($event) {
        this.renderer.invokeElementMethod(this.elRef.nativeElement, 
            'dispatchEvent', 
            [new CustomEvent('input-blur', { bubbles: true })]);
        // or just 
        // el.dispatchEvent(new CustomEvent('input-blur', { bubbles: true }));
        // if you don't care about webworker compatibility
      }
    }
    

    By adding the BlurForwarder directive to directives: [...] it will be applied to all elements in its template that match the selector.
    The host-listener listens for bubbling input-blur events and calls our event handler:

    @Component({
      selector: 'my-component',
      directives: [BlurForwarder],
      host: {'(input-blur)':'onInputBlur($event)'},
      template: `
    <form>
      <input type="text" [(ngModel)]="xxx">
      <input type="text" [(ngModel)]="yyy">
      <input type="text" [(ngModel)]="zzz">
    </form>`
    }) {
      onInputBlur(event) {
        doSomething();
      }
    }