KatsuYuzuのブログ

.NET の開発をメインとした日記です。

angularjsでショートカットキーを実現してくれるAngular Hotkeys

angularjsでショートカットキーを実現してくれるAngular Hotkeys。githubのショートカットキー諸々と"?"を押した時にでるアレ。
f:id:KatsuYuzu:20150623010731p:plain

環境

  • TypeScript 1.4
  • AngularJS 1.4.1
  • angular-hotkeys 1.4.5

Angular Hotkeys

モジュールを読み込んで、該当のスコープでキーを追加します。

angular.module("app", ["cfp.hotkeys"])

allowInは指定の要素でキーを有効にするかどうか。キーは既定ではINPUT要素で無効になっています。業務系でありがちなファンクションキーを指定する時にはallowInでINPUTを指定しました。

class MainController {

    constructor(
        $scope: ng.IScope,
        $http: ng.IHttpService,
        hotkeys: angular.hotkeys.HotkeysProvider) {

        hotkeys.bindTo($scope)
            .add(
            {
                combo: "s",
                allowIn: ["INPUT"],
                description: "API の呼び出し",
                callback: (event: Event) => {
                    $http.get("api の url")
                        .then(
                        (response: ng.IHttpPromiseCallbackArg<{}>) => {
                            alert(response.data);
                        });
                }
            });

    }

}

オプションでショートカットキーのチートシート("?"を押したときのヘルプ表示)のオンオフも。

angular.module("app", ["cfp.hotkeys"])
    .config(
    ["hotkeysProvider", (hotkeysProvider: angular.hotkeys.HotkeysProvider) => {
        hotkeysProvider.includeCheatSheet = true;
    }])

オマケ

そのままだとせっかくのショートカットキーも隠し機能になっちゃったりするので、ディレクティブで画面表示できるようにして使ってました。

angular.module("app")
    .directive("appDisplayHotkey",
    ["hotkeys", "$timeout", (hotkeys: angular.hotkeys.HotkeysProvider, $timeout: ng.ITimeoutService) => {
        return {
            link: (
                scope: ng.IScope,
                element: ng.IAugmentedJQuery,
                attributes: any,
                controller: any) => {

                var hotkey = hotkeys.get(attributes.appDisplayHotkey);

                if (!hotkey) {
                    return;
                }

                element.text("[" + (<string>(<any>hotkey).format()[0]).toUpperCase() + "]: " + hotkey.description);

                element.on("click",(e: Event) => {
                    // 画面遷移などを動作させるために UI スレッドで実行
                    $timeout(() => {
                        hotkey.callback(e, hotkey);
                    });
                });

            }
        };
    }]);
<ul>
    <li class="btn btn-default" app-display-hotkey="a"></li>
    <li class="btn btn-default" app-display-hotkey="s"></li>
</ul>

f:id:KatsuYuzu:20150623012125p:plain

ソース

github.com

勉強会で紹介しました

clrh.connpass.com

angularjsで通信中に自動的に読み込みバー、くるくるを表示してくれるAngular Loading Bar

angularjsで通信中に自動的に読み込みバー、くるくるを表示してくれるAngular Loading Bar。youtubeで画面上を走る赤いバーのアレ。
f:id:KatsuYuzu:20150623004800g:plain

環境

  • TypeScript 1.4
  • AngularJS 1.4.1
  • angular-loading-bar 0.8.0

Angular Loading Bar

モジュールを読み込むだけで$httpに連動してバーを走らせてくれます。

angular.module("app", ["angular-loading-bar"])

オプションでくるくるのオンオフ、通信が十分に早い時にバーがうるさくならないようにレイテンシーの閾値設定も。

angular.module("app", ["angular-loading-bar"])
    .config(
    ["cfpLoadingBarProvider", (cfpLoadingBarProvider: any) => {
        cfpLoadingBarProvider.includeSpinner = false;
        cfpLoadingBarProvider.latencyThreshold = 0;
    }])

ソース

github.com

勉強会で紹介しました

clrh.connpass.com

jQuery.Validation.Unobtrusiveのsuccess, errorをhandleする方法 #aspnetjp

入力エラーをツールチップなどかっこよく制御したい時に。
f:id:KatsuYuzu:20150301001525g:plain

環境

  • jQuery 1.11.1 or 2.1.1(IE8を含む場合は1.11.1、それ以外の場合は2.1.1)
  • jQuery.Validation 1.13.0
  • Microsoft.jQuery.Unobtrusive.Validation 3.2.2

※記載している名称とバージョンはNuGetを想定

jQuery.Validation.Unobtrusiveのsuccess, errorをhandleする方法

optionsをreadyよりも前に設定しておくことで可能。

$.validator.unobtrusive.options = {
    errorPlacement: function ($error, $element) {
        if ($error.text().length === 0) {
            $element.triggerHandler("onSuccess");
        } else {
            $element.triggerHandler("onError");
        }
    }
};

readyよりも前に設定する理由

jquery.validate.unobtrusive.jsの初期化処理がreadyで実行されていて、その中でformの解析、アタッチが行われているから。

$(function () {
    $jQval.unobtrusive.parse(document);
});

これに気づかないとうんともすんとも言わず、苦労した……軽くぐぐったけどソースみた方が早かった。

errorPlacementの理由

タイミング(リアルタイム)、引数(error, inputElement)的にerrorPlacementが一番都合がいい。success, invalidHandlerでもコールバックが呼ばれているが、タイミングや引数が要件に合わず。これらもソースを見ていたらオプションが指定出来て、コールバックが呼ばれていることに気が付いた。基本、読み込むだけのライブラリだから情報が少なめで。

サンプル

jQuery.Validation.Unobtrusive handle sample - JSFiddle

jQuery.Validation.Unobtrusive handle sample - http://jsfiddle.net/bsq6e1b2/

おまけ:TypeScriptの型定義jQuery.Validation.Unobtrusive.d.ts

TypeScriptでは既存のJavaScriptライブラリももちろん使える。再実装されているわけではなく、インターフェイスやアンビエント宣言で型情報を後付け。メジャーどころはDefinitelyTypedで管理されている。嬉しいことにNuGetでも公開されているので下記の通り*1

PM> Install-Package jquery.TypeScript.DefinitelyTyped
PM> Install-Package jquery.validation.TypeScript.DefinitelyTyped

ところが、jQuery.Validation.Unobtrusive の型定義は公開されておらず、型定義がないと$.validator.unobtrusiveというコードはビルドできない。これに対しては自分で型定義を作ることで対応できる。Scripts\typings\jquery.validation.unobtrusive\jQuery.Validation.Unobtrusive.d.tsを作成する。

Type definitions for jQuery.Validation.Unobtrusive
型定義が公開されていない理由は、やっぱり読み込むだけのライブラリだから……

*1:jsファイルを右クリックして[TypeScript 型指定の検索]というメニューでNuGet検索を開けるがとても時間がかかるのでパッケージマネージャーコンソールがオススメ