Backbone.js でModelの情報をサーバーに保存する (Model情報の永続化) - JavaScript

Backbone.js でModelの情報をサーバーに保存するコードを紹介します。

概要

Backbone.js で作成したモデルはJavaScriptで動作しているため、ローカルマシンでの保存されている情報であり、ページのリロードなどで情報は失われてしまいます。この記事では、Backbone.js で作成したModelの情報をサーバーに保存しデータを永続化するコードを紹介します。

プログラム

コード(HTMLファイル側)

下記のHTMLファイルを作成します。
simple-model-persistent.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title></title>
  <script src="jquery-3.2.1.js"></script>
  <script src="underscore.js"></script>
  <script src="backbone.js"></script>
  <script type="text/javascript">
    $(function () {
      var CData = Backbone.Model.extend({
        urlRoot: './data.ashx',
        defaults: {
          name: '',
          url: '',
          memo: ''
        }
      });

      var TextBoxView = Backbone.View.extend({
        tagName: 'input',
        className: 'inputText',
        id: 'text01',
        attributes: {
          type: 'textbox'
        }
      });

      var SaveButtonView = Backbone.View.extend({
        tagName: 'input',
        className: 'inputButton',
        id: 'button01',
        attributes: {
          type: 'button',
          value: '保存'
        },
        events: {
          'click': 'onClick'
        },
        onClick: function (event) {
          var text = $('#text01').val();
          var data = new CData({
            name: 'iPentec',
            url: 'http://www.ipentec.com',
            memo: text
          });

          data.save({ content: "Acroquest" }, {
            success: function (model, resp) {
              $('#output').html(JSON.stringify(resp));
            },
            error: function (model, resp) {
              alert('エラー:送信に失敗しました。' + resp);
              return false;
            }
          });
        }
      });

      var ClearButtonView = Backbone.View.extend({
        tagName: 'input',
        className: 'inputButton',
        id: 'button02',
        attributes: {
          type: 'button',
          value: 'クリア'
        },
        events: {
          'click': 'onClick'
        },
        onClick: function (event) {
          $('#text01').val('');
        }
      });

      var FetchButtonView = Backbone.View.extend({
        tagName: 'input',
        className: 'inputButton',
        id: 'button03',
        attributes: {
          type: 'button',
          value: '読み込み'
        },
        events: {
          'click': 'onClick'
        },
        onClick: function (event) {
          var gdata = new CData();
          gdata.fetch({
            cache: false,
            success: function (model, resp) {
              $('#text01').val(model.get("memo"));
              $('#output').html(model.get("name") + ':' + model.get("url"));
              //下記コードでも可
              //$('#text01').val(model.changed.memo);
              //$('#output').html(model.changed.name + ':' + model.changed.url);
            },
            error: function (model, resp) {
              alert('エラー:受信に失敗しました。' + resp);
              return false;
            }
          });
        }
      });

      var mTextBoxView = new TextBoxView;
      $('#InputFrame').append(mTextBoxView.el);
      var mSaveButtonView = new SaveButtonView;
      $('#InputFrame').append(mSaveButtonView.el);
      var mClearButtonView = new ClearButtonView;
      $('#InputFrame').append(mClearButtonView.el);
      var mFetchButtonView = new FetchButtonView;
      $('#InputFrame').append(mFetchButtonView.el);

    });

  </script>
</head>
<body>
  <div id="InputFrame"></div>
  <div id="output"></div>
</body>
</html>

解説

今回のコードでは4つのビューと1つのモデルを作成しています。ビューは以下の役割となっています。
  • TextBoxView : テキストボックス
  • SaveButtonView : [保存]ボタン
  • ClearButtonView : [クリア]ボタン
  • FetchButtonView : [読み込み]ボタン


[保存]ボタンをクリックすると下記のコードが実行されます。テキストボックス"text01"に入力された値を取得します。CDataモデルのインスタンスを作成し、プロパティを設定します。"name", "url"は固定の値ですが、"memo"プロパティにはテキストボックスに入力した値を設定します。
モデルのインスタンス作成後、モデル(data)のsave()メソッドを呼び出します。saveメソッドの呼び出しにより、サーバーにモデルの情報をPOSTで送信します。
  onClick: function (event) {
    var text = $('#text01').val();
    var data = new CData({
      name: 'iPentec',
      url: 'http://www.ipentec.com',
      memo: text
    });

   data.save({ content: "Acroquest" }, {
      success: function (model, resp) {
        $('#output').html(JSON.stringify(resp));
      },
      error: function (model, resp) {
        alert('エラー:送信に失敗しました。' + resp);
        return false;
      }
    });
  }


save, fetchメソッドでのアクセス先指定はモデルで指定します。urlRoot プロパティにアクセス先のページやcgiのURLを指定します。今回のコードでは同じディレクトリにある data.ashx に対してアクセスをします。
var CData = Backbone.Model.extend({
  urlRoot: './data.ashx',
  defaults: {
    name: '',
    url: '',
    memo: ''
  }
});

[読み込み]ボタンをクリックすると下記のコードが実行されます。モデルのfetchメソッドを呼び出すと、saveメソッドを呼び出した際にアクセスしたURLと同じURLにGetリクエストでアクセスします。モデルの情報の取得に成功した場合は、successイベントのコードが実行されます。下記のコードではモデルのプロパティの値を取得し、"memo"プロパティの値はテキストボックスに表示し、"name", "url" の値は画面にテキストで表示します。
URLにはパラメーターは追加されないため、レスポンスがキャッシュされると変更が画面に表示されない不具合が発生しますので、"cache: false" を指定します。
  onClick: function (event) {
    var gdata = new CData();
    gdata.fetch({
      cache: false,
      success: function (model, resp) {
        $('#text01').val(model.get("memo"));
        $('#output').html(model.get("name") + ':' + model.get("url"));

        //下記コードでも可
        //$('#text01').val(model.changed.memo);
        //$('#output').html(model.changed.name + ':' + model.changed.url);
      },
      error: function (model, resp) {
        alert('エラー:受信に失敗しました。' + resp);
        return false;
      }
    });
  }

コード(サーバー側)

サーバー側のコードです。今回はASP.NETのジェネリックハンドラでサーバー側を実装します。
data.ashx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Web.SessionState;

namespace BackboneJsModelSimple
{
  /// <summary>
  /// data の概要の説明です
  /// </summary>
  public class data : IHttpHandler, IRequiresSessionState
  {

    public void ProcessRequest(HttpContext context)
    {
      if (context.Request.HttpMethod == "POST") {
        context.Response.ContentType = "application/x-www-form-urlencoded";

        StreamReader reader = new StreamReader(context.Request.InputStream);
        string str = reader.ReadToEnd();

        context.Session["KEY"] = str;
        
        context.Response.Write(str);
      }
      else {
        if (context.Session["KEY"] != null) {
          string str = context.Session["KEY"].ToString();
          context.Response.Write(str);
        }
        else {
          context.Response.ContentType = "text/plain";
          context.Response.Write("Hello World");
        }
      }
    }

    public bool IsReusable
    {
      get
      {
        return false;
      }
    }
  }
}

解説

POSTされた場合には、POSTされた内容をセッション変数に保存します。逆にGETでアクセスが来た場合には、セッション変数に保存されている文字列を返します。セッション変数のキー名は"KEY"を利用しています。GET時にセッション変数に値が無い場合は"Hello World" の文字列を返します。
POSTされた場合のレスポンスはPOSTで送信された内容と同じ文字列を返します。

実行結果

上記のHTMLファイルをWebブラウザで表示します。下図の画面が表示されます。


テキストボックスに文字列を入力します。"PENGUIN"と入力しました。


テキスト入力後[保存]ボタンをクリックします。data.ashxに対してPOSTが実行され、レスポンス結果がテキストボックスの下部に表示されます。POSTで送信したJSONが表示されていることが確認できます。


[クリア]ボタンをクリックします。テキストボックスがクリアされます。


[読み込み]ボタンをクリックします。data.ashxに対してGETリクエストが実行され、サーバーに保存されている情報を取得します。取得結果がテキストボックスとテキストボックスの下部に表示されます。


サーバーのセッション変数に保存されているため、ページを再度リロードしても同じ値が戻ることを確認します。ページをリロードします。


[読み込み]ボタンをクリックします。先ほどと同じ内容が画面に表示されます。サーバーで保存している情報が取得できていることが分かります。


日本語でも正しく動作します。


著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
最終更新日: 2017-11-14
作成日: 2017-04-27
iPentec all rights reserverd.