knockout.jsを使ってみた。 

# knockout.jsを使ってみた。

とりあえずサンプルも多そうだったのでToDoを実装。

![todo](https://dl.dropboxusercontent.com/u/11228370/s_2013-10-17_18.31.47.png)
[サンプル](http://dl.dropboxusercontent.com/u/11228370/todo/index.html)

・入力したテキストを一覧に表示。
・チェックされた項目は「削除」ボタンが表示されて削除可能。
・一括削除も実装してみた。
・jQueryも連携してみた（特に必要はない）。

backbone.jsよりもわかりやすい。
ただ大掛かりなサイトや複雑なUIはやはりbackbone.jsのほうが向いてそう。

html部分が綺麗にかけるのは良い！

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>todo</title>
    <script type="text/javascript"
        src="http://codeorigin.jquery.com/jquery-1.10.2.min.js">
    </script>
    <script type="text/javascript"
        src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js">
    </script>
    <script>
$(function(){

    //Model
    var TodoModel = function(value){
        self = this;
        self.todo  = ko.observable(value);
        self.check = ko.observable(false);
    };

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

        self.todoList = ko.observableArray(); //todoリスト
        self.todoInputValue = ko.observable(''); //追加todoテキスト

        //追加
        self.addTodo = function(obj, e)
        {
            if( !self.todoInputValue() )return; //空文字の場合は処理しない

            // Todoリストに追加
            self.todoList.unshift( new TodoModel( self.todoInputValue() ) );
            self.todoInputValue('');
        };

        // 削除
        self.removeTodo = function(obj, e)
        {
            // 第1引数にはModel、第2引数にはイベントが渡される
            //self.todoList.remove(obj);
            // thisもobjと同じでmodelを指してる
            self.todoList.remove(this);
        };

        // 一括削除
        self.allClear = function(){
            if ( confirm("チェックされているデータを一括削除します。本当によろしいですか？")){
                // checkされているものだけ削除
                var removeList = self.todoList.remove(function(todo){return ko.utils.unwrapObservable(todo.check)});

                // 削除件数が返ってくる
                if (removeList.length <= 0){
                    alert("削除対象が選択されていません。");
                }
            }
        };

        // なくても良い。アニメーションとか付ける場合
        self.todoFadeIn = function(element, index, data){
            // 他のnodeTypeでも動作するので「要素」のみ対象にする
            if (element.nodeType === 1) {
                $(element).hide().fadeIn(1500);
            }
        };

        self.todoFadeOut = function(element, index, data){
            if (element.nodeType === 1) {
                $target = $(element);
                $target.fadeOut(1500).queue(function() {
                    $target.remove();
                });
            }
        };
    };

    ko.applyBindings( new TodoViewModel() );
});
    </script>

</head>
<body>
    <p>
        <input type="text" value="" placeholder="TODOを入力" data-bind="value: todoInputValue"> <button data-bind="click: addTodo">追加</button> <button data-bind="click: allClear">チェックしている項目を一括削除</button>
    </p>

    <!-- template を使用しないとbeforeRemove等のイベントが発生しない-->
    <ul data-bind="template: {foreach: todoList, visible: todoList().length>0, afterAdd: todoFadeIn, beforeRemove: todoFadeOut}">
        <li>
            <input type="checkbox" data-bind="checked: check">
            <span data-bind="text: todo">Todo</span>
            <button data-bind="visible: $data.check, click: $root.removeTodo">削除</button>
        </li>
    </ul>
</body>
</html>

```