0

I'm trying to create a small Directive to capture the windows global-keyup and then invoke a callback, so I basically captue the global window in a service and the keyup on my Directive:

export class EnterActivationDirective implements OnInit {
  private _enterClicked: Action;

  @Input() public set enterClicked(action: Action) {
    this._enterClicked = action;
  }

  constructor(public el: ElementRef, public windowWrapperService: WindowWrapperService) {
  }

  ngOnInit() {
    this.windowWrapperService.nativeWindow.onkeyup = this.onWindowKeyUp.bind(this);
  }

  private onWindowKeyUp(event: any) {
    if (event.code === 'Enter' && this._enterClicked) {
      this._enterClicked();
    }
  }
}

The Service and Action-Type aren't that interesting, since the Service just passes the native window and the Action-Type is a generic Callback without any parameters or return-value. The logic itself works, but I get some weird effects regarding the binding to the action. So, one of my other Components registers to the Directive:

<div appEnterActivation [enterClicked]="onKeyUp.bind(this)">
  <div>
... Amended

Which then triggers a search-operation:

 public search(): void {
    this.searchInProgress = true;
    const param = this.createSearchParams();
    this.searchStarted.emit(param);
    this.timeReportEntryApiService.searchTimeReportEntries(param)
      .then(f => {
        const newObjects = ArrayMapper.MapToNewObjects(f, new TimeReportEntry());
        this.searchFinished.emit(newObjects);
        this.searchInProgress = false;
      }).catch(f => {
        this.searchInProgress = false;
        throw f;
      });
  }

  public get canSearch(): boolean {
    return this.form.valid && !this.searchInProgress;
  }

  public onKeyUp(): void {
    debugger ;
    if (this.canSearch) {
      this.search();
    }
  }

Not too much logic here, but if the search is started from the callback, it seems like the properties and functions are in place, but they are on some kind of different object:

  • The searchInProgress-property is set tu true, but on the second enter, it is false again
  • I have some animations and bindings in place, none of them are triggered

Since everything is working with a plain button, I'm almost certain it kindahow has to do with the callback and the binding to this.

I researched a bit regarding this bind, but regarding this thread Use of the JavaScript 'bind' method it seems to be needed. I also tested without binding, but then the this is bound to the global window variable.

Community
  • 1
  • 1
Matthias Müller
  • 3,336
  • 3
  • 33
  • 65

2 Answers2

2

Why are you using an @Input? Angular made @Output for such a use case:

template:

<div appEnterActivation (enterClicked)="onEnter()"></div>

class:

export class EnterActivationDirective implements OnInit {

  @Output() 
  public readonly enterClicked: EventEmitter<any> = new EventEmitter();

  @HostBinding('document.keyup.enter')
  onEnter(): void {
      this.enterClicked.emit();
  }

}

No need for difficult checks or wrappers :)

Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • Many thanks, you're absolutely right. That said, it's more of a learning-project for myself, and since Callbacks are in my main-language (C#) such a crucial part, I try to see the workings in TypeScript and its differences. – Matthias Müller Mar 21 '17 at 20:41
  • Hm , I changed my Code to yours, but HostBinding didn't work, so I just kept my service with the callback to the native window-element. Funny enough, it still doesn't work. I will have to dig deeper, probably the window is the issue and not the callbacks? – Matthias Müller Mar 22 '17 at 15:05
1

Since you are using TypeScript you can use arrow function, that manages this correctly.

 public onKeyUp = () => {
    debugger ;
    if (this.canSearch) {
      this.search();
    }
  }

In that case you can just setup the property binding as

[enterClicked]="onKeyUp"

Chandermani
  • 42,589
  • 12
  • 85
  • 88
  • Hm Thanks, thats a cool trick and now the canSearch seems to be set correctly. Interesting enough, the Animations and Bindings are still not showing up as expected. Do you have some good insights or links regarding the Lambdas and their implications regarding the this? – Matthias Müller Mar 21 '17 at 20:45
  • Fat arrow functions are not typescript, it is Javascript. Typescript has access to fat arrow functions because it is a superset of Javascript. – theres.yer.problem Jan 10 '20 at 16:55