knockout.jsチュートリアル自分用メモ

#概要
jQueryから抜け出せないレガシーなエンジニアが、knockout.jsの[公式サイトのチュートリアル](http://learn.knockoutjs.com/#/?tutorial=intro)を実践した際の自分用メモ。
(チュートリアルでやったことをあとで俯瞰できるように、自分なりのメモとか翻訳した文章を加筆したものです。)

#MVVM(Model-View-ViewModel)とはなんぞや？
まず、基本の勉強。
[MVVMフレームワーク「Knockout.js」が超絶便利！！その概要と使いどころなどについて](http://analogic.jp/knockoutjs-summary/)　より
###M(Model)
クライアントサイドのコードの内、HTMLの都合が関係ない部分（ドメイン）のロジックを実装するJavaScriptコード。
Webサービスの呼び出しや、共通して使われる汎用的なコード（ライブラリ）など。
###V(View)
クライアントサイドのコードの内、UIのテンプレートを定義するHTML/CSS。

###VM(ViewModel)
クライアントサイドのコードの内、UIの状態保持、および、UIから呼び出されるメソッドを定義したJavaScriptコード

#公式チュートリアル実践
## Tutorial: Introduction

<p data-height="265" data-theme-id="0" data-slug-hash="wXPgLJ" data-default-tab="js,result" data-user="yanchi4425" data-embed-version="2" data-pen-title="KOJS tutorial1 for myself" class="codepen">See the Pen <a href="https://codepen.io/yanchi4425/pen/wXPgLJ/">KOJS tutorial1 for myself</a> by Yanchi4425 (<a href="https://codepen.io/yanchi4425">@yanchi4425</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## Tutorial: Working with Lists and Collections
<p data-height="265" data-theme-id="0" data-slug-hash="YvEZzX" data-default-tab="js,result" data-user="yanchi4425" data-embed-version="2" data-pen-title="KOJS tutorial2 for myself" class="codepen">See the Pen <a href="https://codepen.io/yanchi4425/pen/YvEZzX/">KOJS tutorial2 for myself</a> by Yanchi4425 (<a href="https://codepen.io/yanchi4425">@yanchi4425</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## Tutorial: Single Page Application

このコードを直接貼り付けても"/mail"が無いので動きません。
動かしたい場合は、[公式のチュートリアルページ](http://learn.knockoutjs.com/#/?tutorial=webmail)で実行する必要があります。

もしくは、以下に本チュートリアルの完成形があります。
http://learn.knockoutjs.com/WebmailExampleStandalone.html
http://learn.knockoutjs.com/mail?folder=inbox
のようにすると一応/mailから返されるデータを見ることができます。

```html:spa.html

    <style>
        body {
            color: black;
        }
        
        .selected {
            background-color: #7f7;
        }
    </style>
    <ul class="folders" data-bind="foreach: folders">
        <!-- CSSバインディングを使用して、選択したクラスを一致するフォルダに適用したり、
            ユーザーがフォルダをクリックするたびにgoToFolderを呼び出すことができます。 -->
        <li data-bind="text: $data, css: {selected: $data == $root.chosenFolderId()}, click: $root.goToFolder"></li>
    </ul>

    <!-- step2 -->
    <!-- Mails grid -->
    <!-- withバインディングは、その中の要素をバインドするときに使用されるバインディング・コンテキストを作成します。 
        この例では、<table>内のすべてがselectedFolderDataにバインドされるため、
        selectedFolderDataを使用する必要はありません。 
        メールの前にプレフィックスとして。 
    -->
    <table class="mails" data-bind="with: chosenFolderData">
        <thead>
            <tr>
                <th>From</th>
                <th>To</th>
                <th>Subject</th>
                <th>Date</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: mails">
            <!-- step3 -->
            <!-- バインドを更新する必要があるため、訪問者がメールグリッドの行をクリックすると、
                ビューモデルが対応するメールをロードするようにする。
                なんで、<tr>要素のクリックバインドを追加する。 -->
            <tr data-bind="click: $root.goToMail">
                <td data-bind="text: from"></td>
                <td data-bind="text: to"></td>
                <td data-bind="text: subject"></td>
                <td data-bind="text: date"></td>
            </tr>
        </tbody>
    </table>

    <!-- step3 -->
    <!-- 選択されたメールの内容を表示する -->
    <!-- Chosen mail -->
    <div class="viewMail" data-bind="with: chosenMailData">
        <div class="mailInfo">
            <h1 data-bind="text: subject"></h1>
            <p>
                <label>From</label>:
                <span data-bind="text: from"></span>
            </p>
            <p>
                <label>To</label>:
                <span data-bind="text: to"></span>
            </p>
            <p>
                <label>Date</label>:
                <span data-bind="text: date"></span>
            </p>
        </div>
        <!-- htmlバインディングの使用に注目してください。これにより、
            メールコンテンツの改行やHTMLマークアップを画面上に表示することができます -->
        <p class="message" data-bind="html: messageContent" />
    </div>

    <script src="./jquery.min.js"></script>
    <script src="./sammy-latest.min.js"></script>
    <script src="./knockout-3.4.0.js"></script>
    <script>
        function WebMailViewModel() {
            // Data
            var self = this;
            self.folders = ['index', 'Archive', 'Sent', 'Spam'];
            self.chosenFolderId = ko.observable();
            // step2
            // メールグリッドと紐付ける
            self.chosenFolderData = ko.observable();

            // step3
            // メールデータと紐付ける
            self.chosenMailData = ko.observable();

            // ビヘイビア
            // フォルダの内容を表示
            // step4でSammy.jsを使用するため削除
            // self.goToFolder = function(folder) {
            //     // folderの中身：'index', 'Archive', 'Sent', 'Spam'のクリックされたやつ
            //     self.chosenFolderId(folder)

            //     // step3
            //     // メールの表示を停止する
            //     self.chosenMailData(null);
            //     // step2
            //     // jQueryが必要
            //     // ユーザーがフォルダに移動するたびに、Ajaxリクエストを実行してselectedFolderDataにデータを設定します。
            //     // nullが設定された場合は非表示になる。
            //     $.get('/mail', {
            //         folder: folder
            //     }, self.chosenFolderData);
            // };
            //step4 sammyjs化
            self.goToFolder = function(folder) {
                // urlの末尾に#folder名を追加する
                // location.hashはJSの標準
                location.hash = folder;
            }

            // メールの内容を表示
            // step4でSammy.jsを使用するため削除
            // self.goToMail = function(mail) {
            //     // 該当のフォルダを選択状態にする
            //     self.chosenFolderId(mail.folder);
            //     // フォルダの表示を停止する
            //     self.chosenFolderId(null);
            //     // ajaxでメールの内容を取得して表示する
            //     $.get('/mail', {
            //             mailId: mail.id
            //         },
            //         self.chosenMailData);
            // }
            // step4 sammyjs化
            self.goToMail = function(mail) {
                location.hash = mail.folder + '/' + mail.id;
            }

            // step2
            // Inboxをデフォルト表示
            // step4で削除
            // #付きのURLで外部からアクセスした際に、Inboxにリダイレクトされてしまうため。
            // かわりにSammy内で処理する
            // self.goToFolder('Inbox');

            // step4
            // Sammy.jsを使ってクライアントサイドでルーティング
            Sammy(function() {
                // フォルダの内容表示
                this.get('#:folder', function() {
                    //フォルダに移動
                    self.chosenFolderId(this.params.folder);
                    // メールの内容を非表示に
                    self.chosenMailData(null)
                        // Ajaxでデータ取得
                    $.get("/mail", {
                        mailId: this.params.mailId
                    }, self.chosenFolderData);
                });
                // メールの内容表示
                this.get("#:folder/:mailId", function() {
                    // メールの内容に移動
                    self.chosenFolderId(this.params.folder);
                    // フォルダの内容を非表示に
                    self.chosenFolderData(null);
                    // Ajaxでデータ取得
                    $.get("/mail", {
                        mailId: this.params.mailId
                    }, self.chosenMailData);
                });

                //初期表示
                this.get('', function() {
                    this.app.RunRoute('get', '#Inbox')
                });
            }).run();
        }

        ko.applyBindings(new WebMailViewModel());
    </script>

```

残る２つのチュートリアルはまた後日。