さっしーブログ

埼玉県在住のシステムエンジニアです。基本的には技術的な内容を中心に発信していきます。

knockout.js チュートリアル 【Single page applications】

目次

本記事はknockout.jsの公式サイトにある以下のチュートリアルを実施した備忘録です。 learn.knockoutjs.com

Step1

メールボックスのナビゲーションバーを表示するサンプルプログラム

サンプルコード

cssバインディングを利用して選択したフォルダに対してclass="selected"を動的に設定している。

※実際のサンプルコードでは内部的にCSSが適用されるためきれいにスタイリングされているが本サンプルプログラムはCSSを適用していないためご了承ください。

sample.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script>
<script type="text/javascript" src="sample.js" defer="defer"></script>
<title></title>
</head>
<body>
<ul class="folders" data-bind="foreach: folders">
  <li data-bind="text: $data, css: {selected: $data == $root.chosenFolderId()}, click: $root.goToFolder"></li>
</ul>
</body>
</html>

sample.js

function WebmailViewModel() {
  // Data
  var self = this;
  self.folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
  self.chosenFolderId = ko.observable();
  self.goToFolder = function(folder) {
    self.chosenFolderId(folder);
  };
};

ko.applyBindings(new WebmailViewModel());

Step2

メールクライアント構築にてメールボックスの内容を取得して表形式で表示するサンプルプログラム

サンプルコード

クリックするとgoToFolder()の引数に選択されたfolderIdが渡るためフォルダごとに取得してくるデータを振り分けることができる data-bindにwithバインディングを指定することで指定したViewModelにバインドさせることができるため、そのViewModelに定義されているプロパティをそのまま呼び出せる。

※実際のサンプルコードでは内部的に/mailインタフェースを用意しているためデータが取得できるが、 本サンプルコードでは用意していないためそのまま使用しても動作しませんのでご了承ください。

sample.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script>
<script type="text/javascript" src="sample.js" defer="defer"></script>
<title></title>
</head>
<body>
<ul class="folders" data-bind="foreach: folders">
  <li data-bind="text: $data, css: {selected: $data == $root.chosenFolderId()}, click: $root.goToFolder"></li>
</ul>
<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">
    <tr>
      <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>
</body>
</html>

sample.js

function WebmailViewModel() {
  var self = this;
  self.folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
  self.chosenFolderId = ko.observable();
  self.chosenFolderData = ko.observable();
  self.goToFolder = function(folder) {
    self.chosenFolderId(folder);
    $.get('/mail', { folder: folder }, self.chosenFolderData);
  };

  self.goToFolder('Inbox');
};

ko.applyBindings(new WebmailViewModel());

Step3

個々のメールの内容を表示する機能を追加したサンプルプログラム

サンプルコード

htmlバインディング(data-bind="html: ~")を利用することでメール内容の改行などをきれいに表示することができる。 ko.observable()を設定したプロパティにnullを設定するとそのデータは表示されないことが分かった。

※実際のサンプルコードでは内部的に/mailインタフェースを用意しているためデータが取得できるが、 本サンプルコードでは用意していないためそのまま使用しても動作しませんのでご了承ください。

sample.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script>
  <script type="text/javascript" src="sample.js" defer="defer"></script>
  <title></title>
</head>
<body>
  <ul class="folders" data-bind="foreach: folders">
    <li data-bind="text: $data, css: {selected: $data == $root.chosenFolderId()}, click: $root.goToFolder"></li>
  </ul>
  <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">
      <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>
    <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>
      <p class="message" data-bind="html: messageContent" />
    </div>
  </table>
</body>
</html>

sample.js

function WebmailViewModel() {
  var self = this;
  self.folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
  self.chosenFolderId = ko.observable();
  self.chosenFolderData = ko.observable();
  self.chosenMailData = ko.observable();
  self.goToFolder = function(folder) {
    self.chosenFolderId(folder);
    self.chosenMailData(null);
    $.get('/mail', { folder: folder }, self.chosenFolderData);
  };
  self.goToMail = function(mail){
    self.chosenFolderId(mail.folder);
    self.chosenFolderData(null);
    $.get("/mail", { mailId: mail.id }, self.chosenMailData);
  };
  self.goToFolder('Inbox');
};

ko.applyBindings(new WebmailViewModel());

Step4

Sammy.jsを利用したクライアントサイドのルーティング実装を行ったサンプルプログラム

サンプルコード

Sammy.jsを利用することでクライアント側でのルーティング設定が行えることが分かった。 それ以外のルーティングライブラリと組み合わせても行えるはず。

※実際のサンプルコードでは内部的に/mailインタフェースを用意しているためデータが取得できるが、 本サンプルコードでは用意していないためそのまま使用しても動作しませんのでご了承ください。

sample.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script>
    <script type="text/javascript" src="sample.js" defer="defer"></script>
    <title></title>
  </head>
  <body>
    <script src="/scripts/lib/sammy.js" type="text/javascript"></script>
    <ul class="folders" data-bind="foreach: folders">
      <li data-bind="text: $data, css: {selected: $data == $root.chosenFolderId()}, click: $root.goToFolder"></li>
    </ul>
    <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">
          <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>
        <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>
        <p class="message" data-bind="html: messageContent" />
      </div>
    </table>
  </body>
</html>

sample.js

function WebmailViewModel() {
  var self = this;
  self.folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
  self.chosenFolderId = ko.observable();
  self.chosenFolderData = ko.observable();
  self.chosenMailData = ko.observable();
  self.goToFolder = function(folder) { location.hash = folder };
  self.goToMail = function(mail) { location.hash = mail.folder + '/' + mail.id };

  Sammy(function() {
    this.get('#:folder', function() {
      self.chosenFolderId(this.params.folder);
      self.chosenMailData(null);
      $.get("/mail", { folder: this.params.folder }, self.chosenFolderData);
    });

    this.get('#:folder/:mailId', function() {
      self.chosenFolderId(this.params.folder);
      self.chosenFolderData(null);
      $.get("/mail", { mailId: this.params.mailId }, self.chosenMailData);
    });

    this.get('', function() {this.app.runRoute('get', '#Inbox')});
  }).run();
};

ko.applyBindings(new WebmailViewModel());

記事トップは以下になります。

www.sassy-blog.com