孤独プログラマー譚

孤独死が近い。

jQueryでMVVM

案件によっては、自由にJSフレームワークを使えないことがあるかもしれない。
既存システムがjQueryだけで作られているので、それを踏襲する必要があるかもしれない。

そんな時、jQueryでMVVM…双方向データバインディングが出来ると、作業が楽になる。

以下のページで、超便利なラッパークラスが紹介されてた!

var Observable = (function () {
    function Observable(obj) {
        if (obj == null) return;
        for (var p in obj) {
            Object.defineProperty(this, p, createDescriptor(p, obj[p]));
        }
    }
    function createDescriptor(key, value0) {
        var value = value0;
        return {
            get: function () {
                return value;
            },
            set: function (v) {
                if (value === v) return;
                value = v;
                $(this).trigger("property_is_changed", [key, v]);
            },
            enumerable: true,
            configurable: true
        };
    }
    return Observable;
})();

連想配列JavaScriptで言うオブジェクト)でViewModelを作り、それを上記クラスでラッピングする。

<ul>
  <li><input data-model-key="num1"></li>
  <li><input data-model-key="num2"></li>
  <li><span data-model-key="total"></span></li>
  <li><span data-model-key="total2"></span></li>
</ul>
var model = (function(){
  var reload_view_is_finished;

  var model = {
    num1: 0,
    num2: 0,
    total: 0,
    reload_model: function(){
      reload_view_is_finished = false;

      this.total = parseInt(this.num1) + parseInt(this.num2);
    },
    reload_view: function(){
      if (reload_view_is_finished === true) { return; }
      reload_view_is_finished = true;

      $('[data-model-key="num1"').val(this.num1);
      $('[data-model-key="num2"').val(this.num2);
      $('[data-model-key="total"').text(this.total);
    },
  };
  return model;
}());

var observable_model = new Observable(model);
$(observable_model).on('property_is_changed', function(){
  this.reload_model();
  this.reload_view();
});

observable_model のプロパティに値の変更があれば、property_is_changed イベントが発火される。
その結果、reload_model() と reload_view() が実行される。

$(function(){
  // 初期表示
  $(observable_model).trigger('property_is_changed');

  $('input').on('change', function(){
    var key = $(this).attr('data-model-key');
    var value = $(this).val();
    observable_model[key] = value;
  });
});

フィールドに入力があれば、自動で ViewModel に反映される。
反映された ViewMoel から property_is_changed イベントが発火されるので、reload_view() で画面に反映される。

これで、開発がだいぶ楽になってくれるはず…。