born2net
born2net

Reputation: 24943

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

Upvotes: 17

Views: 19880

Answers (3)

Flep
Flep

Reputation: 301

This solution is working for Angular 18:

use (focusout)="focusOut($event)"

The beautiful thing is, you can use the (focusout) on a field level, but also on higher levels like on the form to capture the focusout of all its fields.

Example:

in the .HTML file:

<input matInput type="text" formControlName="avatar_name (focusout)="focusOut($event)">     

       

in the .ts file:

focusOut(event: any): void {
    // your logic
}

Upvotes: 0

TrickySituation
TrickySituation

Reputation: 378

Why not use focusout it bubbles by default in the DOM

Here's a simple directive that catches focusout and checks if input value is blank, then sets value to zero:

@Directive({
  selector: '[blankToZero]'
})
export class BlankToZeroDirective {
  constructor(private elementHost: ElementRef) { }

  @HostListener('focusout')
  ensureInput(): void {
    if (Util.isNullOrEmpty(this.elementHost.nativeElement.value)) {
      this.elementHost.nativeElement.value = 0;
    }
  }
}

Upvotes: 13

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657108

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();
  }
}

Upvotes: 28

Related Questions