SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

TypeScriptでknockout.jsを使う・その3~各種イベント発生時のバインディング~

今度は、イベント発生時にViewModelのメソッドを呼び出すようなバインディングをしてみたいと思います。

まずは、DOM要素をクリックした時に特定のメソッドを呼び出す、clickバインディングを使ってみます。

clickバインディング

以下のように、data-bind属性で「click: メソッド名」と書くと、DOM要素のクリック時に指定したメソッドを呼び出すことができます。

<button data-bind="click: addCount">Click</button>

以下のサンプルコードでは、button要素または画面下部のspan要素をクリックすると、VMのaddCountメソッドが実行されます。
addCountメソッドでは、this.countプロパティの値のインクリメントをしています。

app.ts
/// <reference path="scripts/typings/knockout/knockout.d.ts" />

class AppViewModel {
    count: KnockoutObservable<number>
        = ko.observable<number>(0);
    addCount() {
        var current = this.count(); // 現在のカウント数を取得
        this.count(current + 1);    // カウント数を更新
    }
}

window.onload = () => {
    var viewModel = new AppViewModel();
    ko.applyBindings(viewModel);
};
index.html
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>TypeScript HTML App</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="Scripts/knockout-3.2.0.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <h2>ボタン押下時のイベント処理</h2>
    <span data-bind="text: count"></span>回クリックされました。<br />
    <button data-bind="click: addCount">Click</button><br />
    <span data-bind="click: addCount">button以外でもclickバインディングできます。</span>
</body>
</html>


実行してみると、buttonクリックやテキストクリック時にaddCountメソッドが呼び出され、クリック回数の表示がインクリメントされていくことが確認できるかと思います。
f:id:minami_SC:20150304002645p:plain

KnockoutObservable型の値を扱うときの注意
ここで注意が必要なのは、KnockoutObservable型の値の扱い方です。
KnockoutObservable型のプロパティは、プロパティ値の取得/設定は、プロパティ名をメソッドとして呼び出すことで行います。
プロパティの設定時などは、ついうっかり普通に代入してしまったりしがちなので、特に注意が必要かと思います。




その他のイベントとのバインディング

click以外のイベントにバインドしたい場合は、eventバインディングを使用します。

eventバインディング

eventバインディングでは、以下のように「event:」の後にイベント名とコールバックに使用する関数名を記述します。

<div class="fillRect" data-bind="event: {mousemove: onMousemove}">

コールバック関数は、以下のようなフォーマットで作成します。

onMousemove(data, event) {
}


以下のサンプルコードでは、ベージュ色の背景のdiv要素上でマウスカーソルを動かすと、div上での相対座標を表示します。

app.ts
/// <reference path="scripts/typings/knockout/knockout.d.ts" />

class AppViewModel {
    posText: KnockoutObservable<string>
        = ko.observable<string>("");

    onMousemove(data, event: MouseEvent) {
        var str = "(" + event.offsetX.toFixed(2) + ", " + event.offsetY.toFixed(2) + ")";
        this.posText(str);
    }
}

window.onload = () => {
    var viewModel = new AppViewModel();
    ko.applyBindings(viewModel);
};
index.html
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>TypeScript HTML App</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="Scripts/knockout-3.2.0.js"></script>
    <script src="app.js"></script>
    <style type="text/css">
        .fillRect {
            width: 300px;
            height: 300px;
            background: beige;
        }
    </style>
    
</head>
<body>
    <h2>eventバインディングのテスト</h2>

    <div class="fillRect" data-bind="event: {mousemove: onMousemove}">
        <span data-bind="text: posText"></span>
    </div>
</body>
</html>

実行結果は以下の通り。
f:id:minami_SC:20150304002712p:plain



で、今回扱ったようなイベント発生時のコールバックには、JavaScriptならではの大きな落とし穴があるのですが、その辺はまた次回。