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() で画面に反映される。
これで、開発がだいぶ楽になってくれるはず…。