完敗だぜ!knockoutでノックアウト – Todoアプリ編1

みなさんこんにちは。江口です。

前回 に引き続き Knockout についてのエントリです。今回からは Knockout を使って簡単な Todo 管理アプリケーションを作成しながら、基本的な機能と使い方について紹介します。

作成する Todo 管理アプリケーションの完成形のデモは こちら でご覧になれます。

ソースコードは こちら(Github) から閲覧、ダウンロード出来ます。

Veiw の作成

それでは、まず最初に View として次のような何の変哲もない HTML(todo.html) と CSS(todo.css) を作成しておきます。

<!DOCTYPE html>
<html>
<head>
    <title>Todo</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" media="all" href="todo.css">
    <script type="text/javascript" src="knockout-2.2.1.js"></script>
</head>
<body>

<div id="content">
    <h1>Todo</h1>

    <form>
        <input type="text" placeholder="todo"/>
        <input type="submit" value="add"/>
    </form>

    <div id="todoList">
        <span class="counter">0 items</span><span class="archive redLink">archive</span>

        <ul>
            <li class="todoItem">
                <input type="checkbox"/>
                <span class="summary"></span>
                <span class="delete redLink">delete</span>
            </li>
        </ul>
    </div>
</div>
<script type="text/javascript" src="todo.js"></script>
</body>
</html>

 Knockout の導入

Knockout を導入するには、他の一般的な JavaScript のライブラリと同じくダウンロードページからファイルをダウンロードし script タグでパスを指定します。jQuery などの他のライブラにには依存しないので単体で使用出来ます。Knockout のファイルは CDN からでも公開されているのでそちらを利用する方法もあります。ここではこのエントリの執筆時点の最新バージョンである 2.2.1 を使用します。

<script type="text/javascript" src="knockout-2.2.1.js"></script>

ViewModel の作成

まず最初に todo.js に VewModel を定義して input に入力された内容を Todo として追加できるようにしていきます。内容が入力されてから Todo を追加するまでの処理の流れを整理すると次のようになります。

  1. 入力フォームのボタンがクリックされる
  2. input 要素の値を取り出して Todo オブジェクトを作成する
  3. Todo のリストに Todo を追加する
  4. 入力欄を空にして次の入力に備える

入力フォームのボタンがクリックされた時の処理

では早速、入力フォームのボタンが Click された時に呼び出される関数 addTodo を追加しましょう。その後、この addTodo 関数をフォームの submit イベントに対してバインドします。関数を要素のイベントに対してバインドすると、その要素に対してイベントが発生した時にバインドされた関数が呼び出されるようになります。

Knockout では、HTML と ViewModel とのバインドに data-bind という専用の属性を使用します。data-bind 属性の値にはバインディングの種類とその要素とバインドするオブジェクトや関数を指定することができます。また、バインディングはカンマ区切りで複数指定することも可能です。

function ViewModel() {
    var self = this;

    self.addTodo = function () {
    };
}

ko.applyBindings(new ViewModel());
<form data-bind="submit: addTodo">

 ViewModel を引数に ko.applyBindings を呼び出すことで Knockout が作動し HTML 上の要素と ViewModel オブジェクトとのバインドを行います。

Todo オブジェクトを作成する

次に、addTodo 関数の中身を追加していきます。下の例は jQuery を使って input 要素から値を取り出すコードですが、Knockout を使う場合はこのように DOM から要素を取得して値を取り出すというようなことは基本的に行いません。

var text = $('form input[type="text"]').val();

 では、どのように input 要素の値を取り出すのかというと、ここでも Knockout のバインド機能を使用します。ViewModel のプロパティと対象の input 要素をバインドすることで、input に入力された値と ViewModel のプロパティの値を同期して取り出すことができます。そして、Knockout ではその仕組みを実現するために observable という機能が提供されています。observable は ko.observbale メソッドを呼び出すことで作成することができます。引数を指定すると observable の初期値を設定することができます。

function ViewModel() {
    var self = this;

    self.todoSummary = ko.observable('');
    self.addTodo = function () {
    };
}

ko.applyBindings(new ViewModel());

 上のように ViewModel に対して todoSummary プロパティを observable として定義したら、次にこのプロパティを input 要素と value バインディングを使用してバインドします。value バインディングは input / textarea / select タグの要素に使用できるバインディングです。

<input type="text" data-bind="value: todoSummary" placeholder="todo"/>

 これでinput 要素に文字が入力されると、todoSummary は Knockout により自動的に入力された値に更新されるようになりました。

次は todo オブジェクトを作成する処理を addTodo メソッドに定義します。実は observable の実態は関数なので、引数を与えずに呼び出すことで現在の値を取り出すことができます。

self.addTodo = function () {
    var todo = {
        summary: self.todoSummary()
    };
};

 Todo オブジェクトをリストに追加する

Todo オブジェクトを UI に表示するには、Todo のリストを定義して View にバインドします。そこで、Todo オブジェクトを格納する配列 todoList を ViewModel に定義します。todoList は View とバインドする必要があるので、Observables として生成する必要がありますが、Knockout には observable の配列版である observableArray というのがあるのでこちらを使用します。observableArray は ko.observbaleArray メソッドを呼び出すことで作成できます。

self.todoList = ko.observableArray(); // Todo のリスト
self.addTodo = function () {
    var todo = {
        summary: self.todoSummary()
    };

    self.todoList.push(todo); // リストに Todo を追加
};

observableArray を View の要素とバインディングするには主に foreach バインディングを使用します。foreach バインディングはバインドした配列の長さと同じ数だけ、要素を繰り返し生成することができます。主に配列をリストやテーブルとして View 上に表示するのに使用することができます。下の例では、 foreach バインディングを指定している ul 要素以下の li が todo と同じ数だけ生成されます。

さて、todoList とリスト要素をバインドするには次のように記述します。foreach ブロック内では、配列要素( ここでは todo のオブジェクト)のプロパティを直接指定することができるので todo オブジェクトの summary プロパティと span のテキスト要素をバインドするには data-bind=”text: summary” を属性に追加します。

<ul data-bind="foreach: todoList">
    <li class="todoItem">
        <input type="checkbox"/>
        <span class="summary" data-bind="text: summary"></span>
        <span class="delete redLink">delete</span>
    </li>
</ul>

 

これで todoList に対して新しい todo オブジェクトを追加すると、UI が自動的に更新され Todo が UI 上に表示されるようになります。

入力欄を空にする

最後に、入力欄の内容を空にします。 input の要素の値を変更するには、これとバインドしている todoSummary に新しい値を引数として指定して実行します。ここでは、値を空にしたいので空文字列を与えて実行します。

self.addTodo = function () {
    var todo = {
        summary: self.todoSummary()
    };

    self.todoList.push(todo);
    self.todoSummary(''); // 入力欄を空にする
};

 value バンディングは observable と双方向にバインドされるので、todoSummary の状態を変更すると Knockout が変更を検知して UI 上の値を自動的に同期します。

ここまでの todo.js の内容をまとめると次のようになります。

(function () {
    function ViewModel() {
        var self = this;

        self.todoList = ko.observableArray();
        self.todoSummary = ko.observable('');
        self.addTodo = function () {
            var todo = {
                summary: self.todoSummary()
            };

            self.todoList.push(todo);
            self.todoSummary('');
        };
    }

    ko.applyBindings(new ViewModel());
})();

 

以上、今回は Todo 管理アプリケーションを作りながら Knockout の基本的な機能について紹介してきました。次回は今回紹介しきれなかった機能についてこの Todo 管理アプリケーションに手を加えながら紹介する予定です。おたのしみに。


完敗だぜ!knockoutでノックアウト 記事

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる