Daisuke's TechBlog

日々の仕事で得た技術的なことを書いてきます

backbone.js 実装解説

hiromitsu-daisuke.hatenablog.com

前回backbone.jsで実装したコードについて書きました。 今回はその解説です。

See the Pen backbone.js checkbox sync by HIROMITSU Daisuke (@daisuke718) on CodePen.


なお、対戦チームと場所のオブジェクトは同じ構造になっているので、
対戦チーム側で解説します。

Backbone.jsで提供されている、以下の基底クラスを実装しています。

  • Model
  • View
  • Collection (Controllerじゃないです)

Model

/**
 * 対戦チームモデル
 */
var Match = Backbone.Model.extend({
    defaults: {
        matchCd: '',
        relation : new Array(),
        siblings: {},
        checked: false
    }
});

まずはモデルです。
javascriptなので特に変数を定義する必要はないですが、 分かりやすくするために記載しています。

下記それぞれの意味です。

変数 意味
matchCd 対戦チームの識別子となるID
relation 関連のある場所コードを管理する配列
siblings 関連のある場所コードをキーとして、さらにその関連の対戦チームを管理するオブジェクト。
checked 選択状態を管理します。

View

/**
 * 対戦チームビュー(チェックボックス)
 */
var MatchView = Backbone.View.extend({
    model: Match,
    events: {
        'change' : 'onChange' ,
        'click'  : 'onClick'
    },
    initialize: function() {
        this.render();
    },
    render: function() {
        $(this.el).prop('checked', this.model.get('checked'));
    },
    onChange: function() {
        var checked = $(this.el).prop('checked');
        this.model.set('checked', checked);
    },
    onClick: function() {
        var checked = $(this.el).prop('checked');
        this.model.set('checked', checked);
        var placeCds = this.model.get('relation');
        var siblings = this.model.get('siblings');
        
        // 関連のあるタイトルチェックボックスを変更する
        $.each(placeCds, function() {
            var placeCd = this;
            var placeCheckBox = $('#place_area').find(':checkbox[value=' + placeCd + ']');
            
            if ( checked ) {
                // イベント発生元がチェックOFF⇒チェックONの場合
                placeCheckBox.prop('checked', true).change();
            } else {
                // イベント発生元がチェックON⇒チェックOFFの場合
                var sibling = siblings[placeCd];
                
                // タイトルを親と見た場合の兄弟のチェック状態を確認する
                var siblingChecked = false;
                $.each(sibling, function() {
                    var siblingMatchCd = this;
                    var siblingMatchCheckBox = $('#match_area').find(':checkbox[value=' + siblingMatchCd + ']');
                    if ( siblingMatchCheckBox.prop('checked') ) {
                        // チェックONの場合
                        // フラグをあげてループを抜ける
                        siblingChecked = true;
                        return false; // break;
                    }
                });
                
                // 兄弟がすべてチェックOFFの場合親をOFFにする
                if ( ! siblingChecked ) {
                    placeCheckBox.prop('checked', false).change();
                }
            }
        });

    },
});

/**
 * 対戦チームリストビュー(対戦チームチェックボックスビューのリスト)
 */
var MatchListView = Backbone.View.extend({
    el: '#match_area',
    collection: MatchList,
    initialize: function() {
        this.collection.each(function(match) {
            var matchEl = this.$(':checkbox[value="' + match.get('matchCd') +'"]');
            var view = new MatchView({el: matchEl, model: match});
        });
    }
});

続いてViewです。 チェックボックスそのもののViewオブジェクトと
対戦チームのチェックボックス群を管理するViewオブジェクトを定義しています。

Viewはeventsというプロパティでクリックイベントなどを自クラスの関数と結びつけることができます。
あと、elというプロパティでCSSセレクタによりhtmlの要素とのひも付けができます。
また、modelやcollectionプロパティで扱うオブジェクトクラスを指定することができます。
ここで指定したmodelやcollectionはオブジェクト内でthis.modelやthis.collectionというふうに使うことができます。

MatchViewのOnClickメソッドが本スクリプトのキモとなる部分ですね。(特に説明はしませんw)
あとMatchListViewの意義ですが、これを定義することでMatchViewのそれぞれのインスタンスを生成することができます。

Collection

/**
 * 対戦チームリスト
 */
var MatchList = Backbone.Collection.extend({
    model: Match
}); 

Collectionです。
javaのListみたいなイメージで使うものです。
modelプロパティにModelクラスを指定することで何のCollectionかを指定することができます。

実行

あとは初期処理のところで初期データ(value値と関連データ)を与えて
インスタンス化をしていってます。

以上です。