Angular execute function two time on events in Chrome

Viewed 70

I have a input field that is executing a function in two event on (blur) and another in (keydown.enter), in both cases the function is saving the data in the server and switching the in put for a <span>, now the problem is that on (keydown.enter) in firefox the function is trigger ones but in chrome the function is trigger two times when i should be only ones.

Template

<input type="text" class="text-field"
  [(ngModel)]="column[item.id]" (blur)="setValue(nameInputDE, 'textDE', column)"
  (keydown.enter)="setValue(nameInputDE, 'textDE', column)"
  *ngIf="column.editModeNameDE && item.id == 'textDE'" #nameInputDE />

Component.ts

  public setValue(item, attr: string, col: KanbanColumn) {
    if (attr == 'myBoardColumnMapping' && item.id == col[attr]) {
      return;
    }
    this.log.trace('setValue(item: ' + item.id + ', attr: ' + attr + ', colID: ' + col.dataField + ')');

    let newVal;

    switch (attr) {
      case 'myBoardColumnMapping':
        col.myBoardColumnMapping = item.id;
        break;
      case 'text':
        col.text = item.value;
        break;
      case 'textDE':
        col.textDE = item.value;
        break;
      case 'wipLimit':
        col.wipLimit = item.value ? item.value : null;
        // if the value is invalid -> do not remove the input
        if (newVal < 1 || newVal > 100) {
          return;
        }
        break;
    }
    this.storeData(col);
  }

so far i have no idea how to fix this issue, firefox only take the first event on the input in this case (keydown.enter) but Chrome take both first (keydown.enter) and then (blur)executing the function two times, any idea how can i avoid this happen.

In the case of creating a directive that listen for the events, the result is the same, because in chrome both event are been triggered, chrome still executing the function two times.

1 Answers

I created a rough example on stackblitz that can show you how to accomplish this using rxjs to listen to the keydown enter event and blur event while only taking the first one of either of those events.

You can experiment further with this by using more of the filtering operators.

The general logic is:

  const listenToKeydownAndBlur = merge(
    fromEvent(this.theInput.nativeElement, 'keydown').pipe(
      filter((ev: any) => {
        return ev.code === 'Enter';
      }),
      tap(ok => {
        this.submitType = 'keydown enter event';
        console.log('keydown enter');
      })
    ),
    fromEvent(this.theInput.nativeElement, 'blur').pipe(
      tap(ok => {
        this.submitType = 'blur event';
        console.log('blur');
      })
    )
  ).pipe(
    first(),
    tap(ok => {
      this.submitted = true
      // Do submit logic!
    })
  )

  listenToKeydownAndBlur.subscribe();
Related