しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC 4 で knockout.js を活用する

これは C# Advent Calendar 2011 用の記事です。
皆さんこんばんは、もうちょっとで今年一年終わりですね。まあ、そんなことはどうでもいいとして Ever17 の箱版プレイしましょうね。

さて、今回は C# Advent Calendar と言いながら JavaScript かよ!という感じですが ASP.NET MVC 4 なので問題ないのですよ!!ASP.NET MVC 4 を入れている人が少ないので知っている人が少なそうですが、標準で knockout.js が NuGet パッケージとして入るようになっています。

knockout.js を分かりやすく説明すると WPF/Silverlight のデータバインディング・ItemsControl・データテンプレートを HTML で実現するためのライブラリです。

デフォルトで入るようになっていますが、参照はされていないので _Layout.cshtml の head タグに以下の 1 行を追加します。

<script src="@Url.Content("~/Scripts/knockout-1.3.0beta.js")" type="text/javascript"></script>

とりあえずしょぼいですが、足し算するようなフォームを knockout.js で作ってみます。まずはスクリプトから。

<script type="text/javascript">
    var viewModel = {
        left: ko.observable(0),
        right: ko.observable(0)
    };

    viewModel.answer = ko.dependentObservable(function () {
        return parseInt(this.left()) + parseInt(this.right());
    }, viewModel);

    ko.applyBindings(viewModel);
</script>

ViewModel に関してはあまり言及しませんが、left と right というプロパティを用意します。ko.observable は WPF/Silverlight の DependencyProperty と同じものだと考えてください。これで定義したプロパティは変更通知が動作するようになります。

そして answer では ko.dependentObservable を使って定義しています。これは WPF では IValueConverter と IMultiValueConverter に相当していて、値に対して何らかの変換を行って返すことが出来ます。ちなみに、内部で使ってるプロパティの値が変わった時にもちゃんと追従してくれます。

そして HTML を用意します。注意点としては先程のスクリプトよりも前に書いておく必要があります。

<input type="text" data-bind="value: left" /> + <input type="text" data-bind="value: right" /> = <span data-bind="text: answer"></span>

HTML5 の Custom Data Attribute を使ってバインディングを定義します。data-bind 属性は {Binding} 式と同じものだと思ってください。バインディングのターゲットとして value や text など以外に任意の属性を指定することもできます。詳しくは公式サイトのドキュメントを見てくださいね。

実行すると以下のような感じです。jQuery などで変更されたか調べて、ごりごり書き換えたり指定はいませんが、リアルタイムで値が更新されます。

さて、これで終わってしまうと C# 関係ねえと言われそうというか、既に言われてそうなので ASP.NET MVC と連携させます。JavaScript なので JSON で値を返すと簡単に扱えるようになります。そして ASP.NET MVC には JsonResult があるので、簡単に JSON で返すことが出来ますね。

public ActionResult IndexAjax()
{
    var list = new[]
    {
        new { name = "北兄者", score = 100 },
        new { name = "兄者", score = 150 },
        new { name = "抱き枕兄者", score = 100 }
    };

    return Json(list, JsonRequestBehavior.AllowGet);
}

これで Json を出力することが出来ます。AllowGet を忘れないようにしてください。

そして JavaScript と HTML を書いていきます。knockout 1.3.0 からはテンプレートエンジンが内蔵されているので、jQuery Template を必要としなくなりました。

<ul data-bind="foreach: items">
    <li>名前: <span data-bind="text: name"></span>, スコア: <span data-bind="text: score"></span></li>
</ul>

<script type="text/javascript">
    $(function () {
        $.getJSON("@Url.Action("IndexAjax")", function (data) {
            var viewModel = {
                items: ko.observableArray(data)
            };

            ko.applyBindings(viewModel);
        });
    });
</script>

data-bind 属性で foreach を指定すると中身をテンプレートとして扱ってくれます。この辺りは DataTemplate と同じような感じで使い勝手が良いですね。もちろん変更追跡が有効になっているので、ko.observableArray にアイテムを追加すると動的に追加されます。

ASP.NET MVC だから HTML5 や JavaScript のライブラリが使えないとか、使うのがめんどくさいとかいうことは全くないのですよ!!