Angular CapsLock Directive

Home / Angular CapsLock Directive

In my previous post, I put together a little demo showing how to detect if capslock is depressed and how to warn the user. To make this a bit more useful and reusable, I rolled it into an Angular 1.x directive.


The differences with the Angular approach and the previous approach are two fold.

First, typically with Angular applications, for operations that are global, we want to manage these states and events with a singleton service.

Second, to avoid direct DOM manipulation, most all DOM interaction is provided via a directive. Introducing a directive provides a great opportunity for reuse.

Ideally, I want the directive to be able to be applied to any text input as an attribute and then to be able to either inject into the DOM a warning message, or to pass in a selector for displaying a common error message. Like this:

<label>Password 1</label>
<input id="password1" type="password" caps-lock />

<label>Password 2</label>
<input id="password2" type="password" caps-lock caps-lock-warning="#custom" />
<div id="custom" class="warning">This is a custom warning.  Your caps lock is on!</div>

To facilitate global events, the previous code that relied on $(document) event handlers that were globally attached and only, effectively, usuable within a single scope, I have moved those events into a common service which raises its own event when capslock is pressed. The directive will listen for this Angular event and hide/shown its warning message. By attaching DOM handlers within the service using the $document service, we get these events available within every instance of the capslock directive. The JavaScript listeners broadcast on $rootScope when as appropriate.

$document.keydown(function(e) {
  if (e.which == 20 && capsLockEnabled !== null) {
    capsLockEnabled = !capsLockEnabled;
    console.log("Keydown. CapsLock enabled: " + capsLockEnabled.toString());
    $rootScope.$broadcast('capslockToggle');
  } else if (e.which == 20) {
    $log.log("Keydown. Initial state not set.");
  }
});

$document.keypress(function(e) {
  var str = String.fromCharCode(e.which);
  if (!str || str.toLowerCase() === str.toUpperCase()) {
    $log.log("Keypress. Some control key pressed.");
    return;
  }
  capsLockEnabled = (str.toLowerCase() === str && e.shiftKey) || (str.toUpperCase() === str && !e.shiftKey);
  console.log("Keypress. CapsLock enabled: " + capsLockEnabled.toString());
  $rootScope.$broadcast('capslockToggle');
});

The same mechanisms as in the previous demo are very much intact in the Angular example. The only significant differences are the Angular specifics, which can all be in seen the demo plunk below.

Leave a Reply