Ziv Glazer
Ziv Glazer

Reputation: 826

keystrokes (key bindings) for specific elements in angular 2

what-is-angular2-way-of-creating-global-keyboard-shortcuts

Only that im interested in making the shortcuts binded to a specific element (or a container if you will). The shortcut should only work the user focus is in the element or one of his children, and when the element is removed from the dom, the bindings naturally should remove with it.

I have found some way of doing these which I find not very clean:

/**
* Created by Ziv on 5/23/2016.
*/
import {Injectable} from "angular2/core";

@Injectable()
export class KeyBoardService {

public registerKeyStrokeForElemet(
    strKeyStroke: string,
    fnCallBack: () => void,
    fnIsButtonAvailable: () => boolean,
    element: any,
    bShouldEffectOnlyInContainer: boolean,
    functionThisContext: any): void {

    // Adding tab index property to the container so the events will be raised only when
    // the container is focused
    jQuery(element).prop("tabindex", 1);

    jQuery(element).css("outline", "none");

    jQuery(element).bind(
        'keystrokes', {
            keys: [strKeyStroke]
        }, (e) => {
            // Checking if this event should only happen when the div container is focused
            if (!bShouldEffectOnlyInContainer || jQuery(e.target).is("div")) {
                if (typeof fnIsButtonAvailable !== "function" || fnIsButtonAvailable.apply(functionThisContext, event)) {
                    e.preventDefault();

                    fnCallBack.apply(functionThisContext);
                }
            }
        }
    );

    // If the event should effect all the elements inside the container too,
    // there is a special case when events in jquery keystroke library ignored text inputs.
    // the solution offered by the libraray author is to assign thoose events to them inputs
    // explicitly, which is what were gonna do next
    if (!bShouldEffectOnlyInContainer)
    {
        jQuery(element).find(
                "textarea, :text"
            ).bind(
            'keystrokes',
            {
                keys: [strKeyStroke]
            },
            (e) => {
                if (typeof fnIsButtonAvailable === "function" || fnIsButtonAvailable.apply(functionThisContext, event)) {
                    e.preventDefault();

                    fnCallBack.apply(functionThisContext);
                }
            }
        );
    }
}

}

It relies on using jquery-keystrokes jquery keystrokes Which is a bit old, and generally I find using to much jquery in an angular 2 app pretty dirty, so I am looking for the "angular way" to achieve this

Upvotes: 0

Views: 1832

Answers (1)

Mark Rajcok
Mark Rajcok

Reputation: 364727

This should get you started...

To listen for keystrokes on a DOM element (e.g., a div) you can create an attribute directive that uses

import {Component, Directive, Input, HostBinding, HostListener} from '@angular/core';

@Directive({selector: '[catchkeys]'}) 
export class CatchKeys {
  // add tabindex attribute so host element (e.g., a div) will receive keyboard events
  // https://stackoverflow.com/questions/10722589/how-to-bind-keyboard-events-to-div-elements
  @HostBinding('tabindex') tabIndex = 1;
  @HostListener('keyup', ['$event'])
  onKeyUp(kbdEvent) {
    console.log(kbdEvent);
  }
}

@Component({
  selector: 'child',
  template: `<div catchkeys>child: {{msg}}
      <div>child element</div>
    </div>`,
  directives: [CatchKeys]
})
class Child {
  @Input() msg:string;
}

Plunker


To filter specific keys, pass a list into the CatchKeys directive:

<div catchkeys="someListOfKeys">

Then modify the directive:

@Input() catchkeys:string;  // or maybe use an Array 
ngOnInit() {
  console.log(this.catchkeys);
}
// use this.catchkeys in the onKeyUp() method to filter

Upvotes: 2

Related Questions