edo1z blog

プログラミングなどに関するブログです

Backbone.jsとMarionette

http://backbonejs.org/ここのdevelopバージョンを使ってみます。Underscore.jsに依存します。http://underscorejs.org/ jQueryも使います。

モデル

var Hoge = Backbone.Model.extend({
    defaults:{
        'name': 'taro',
        'age': 20,
        'updateTime': new Date()
    },
    initialize: function(){
        console.log('create hoge : ' + this.cid + ' : ' + JSON.stringify(this));
    }
});

var hoge = new Hoge();
hoge.set({
    name: 'jiro',
    age: 30
});

console.log('hoge : ' + hoge.cid + ' : ' + JSON.stringify(hoge));

こんな感じで、モデルを作成できる。defaultsで初期設定、initializeでコンストラクタの設定ができる。newで、モデルのインスタンスを作成し、setで、各値をインスタンスにセットできる。getで取得できる。hoge.get('name');

var hoge = new Hoge({
    'name': 'saburo',
    'age': 30
});

こんな風に、newのときに、引数に値を渡すことでセットすることもできる。newでインスタンスを作成すると、cidというものが自動的に設定される。これはインスタンスを一意に識別するためのもの。

hoge2 = hoge.clone();

clone()で、インスタンスを複製できる。cidだけは、ユニークとなる。

その他、モデルのメソッド・プロパティは、attributes、clear、has、unsetがある。

モデルに関数を追加するのはこんな感じでできる。

var Hoge = Backbone.Model.extend({
    defaults:{
        'name': 'taro',
        'age': 10,
        'updateTime': new Date()
    },

    initialize: function(){
        console.log('create hoge : ' + this.cid + ' : ' + JSON.stringify(this));
    },

    add_age: function(){
        this.set({age: this.get('age') + 1});
    }
});

var hoge = new Hoge();
hoge.set({
    name: 'jiro',
    age: 20
});
console.log(hoge.get('name') + ' : ' + hoge.get('age'));

hoge.add_age();
console.log(hoge.get('name') + ' : ' + hoge.get('age'));

属性の値を1追加するのに、こんなめんどうな書き方しかできないとは思えないんだけど、this.age ++;とかではエラーになった。 その他、モデルの変化に応じてイベントを発動したり、どこが変化したのかチェックしたり、モデルの変化が妥当な変化かをチェックするバリデーションルールの設定などができる。

モデルのサーバとのやりとり

はて、Ajaxでサーバとやりとりするのも、Bacbone.jsは便利になっているもよう。サーバ側をcakePHPでつくりながら試してみる。

モデルで、サーバとやりとりする際は、APIのURLを設定する。

var Dev = Backbone.Model.extend({
    urlRoot: 'http://local.com/devs/hoge/'
});

あとは、saveメソッドを呼出すだけで、新規作成か更新処理をしてくれるということで、作成処理はPOSTアクセス、更新処理は、PUTアクセスする。saveメソッド呼び出し時に、id属性の指定があれば、更新処理とし、なければ新規作成とする。らしい。

便利そうでありつつ、色々注意が必要そうですが、一旦データ取得から確認してみたい。データ取得は、fetchメソッドらしい。

参考:試して学ぶ Backbone.js入門2この記事は分かり易そう。

cakePHPのcontrollerで下記のようなものをつくりました。Devモデルというのを既に作成済みです。

public function hoge($id = null){
    if(!$this->request->is('ajax')) throw new BadRequestException();
    $this->autoRender = false;

    //取得(fetch)
    if($this->request->is('get')){
        if($id){
            $devs = $this->Dev->findById($id);
        }else{
            $devs = $this->Dev->find('all');
        }
        return json_encode(compact('devs'));
    }

    return null;
}

これにfetchアクセスする、backboneのコードをつくってみます。

var Dev = Backbone.Model.extend({
    urlRoot: 'http://local.com/backborn/devs/hoge/'
});

var dev = new Dev();
dev.fetch({
    success: function(model, response, options){
        console.log(response.devs[0]['Dev']['title']);
    }
});

これでできました。idを渡してみます。

var Dev = Backbone.Model.extend({
    urlRoot: 'http://local.com/backborn/devs/hoge/'
});

var dev = new Dev();
dev.set({id: 3});
dev.fetch({
    success: function(model, response, options){
        console.log(response.devs['Dev']['title']);
    }
});

できました。分かりました。取得後に、parseというのを使って、レスポンスに対して色々やったりするらしい。

コレクション

コレクションは、モデルのリストらしい。

View

viewは、モデルの変更に目を光らせて、レンダリングするやつらしい。モデルが変更されたらBackbone.Eventsによって、Viewに通知されて、その通知内容に基づいてレンダリングする内容をつくるらしい。そして、テンプレートに渡すという流れのようでありんす。つまり、cakePHPのモデルとbackboneのモデルは同じだけど、cakePHPのcontrollerとbackboneのviewが同じで、cakePHPのviewとbackboneのテンプレートが同じみたいな感じかなと思った。

Viewは、モデルやコレクションの変更に目を光らせるだけではなく、DOMの変更にも目を光らせる。そして、一つのViewは、一つのDOMに紐づける必要がある。DOMとの紐づけは、elプロパティが使える。紐づくDOMの条件をelの値として設定することができる。その他、tagName、className、id、attributesなどを設定することで、動的にel属性を作成することができる。elとtagNameとかが同時に設定されている場合、elの設定が優先されるし、el設定が存在しないdomを表している場合は、tagName等が設定されていても、elはundifinedになる。elを設定されている場合は、必ず存在するDOM条件を設定する必要があるようだ。elもtagName等も設定されていない場合は、空のdivがel属性の値になる。新たに作成されたel属性の場合は、el属性が作成された段階ではDOMに追加されないらしい。

HTML

<div id="hoge"></div>

Js

var DevView = Backbone.View.extend({
    el: '#hoge'
});

var dev_view = new DevView();
console.log(dev_view.el);

これのログへの出力結果は、<div id="hoge"></div>となる。

viewのコンテンツを表示するには、renderメソッドを使う。

var DevView = Backbone.View.extend({
    el: '.hoge',
    render: function(){
        this.$el.append('hogehoge');
        return this;
    }
});

var dev_view = new DevView();
dev_view.render();

テンプレートは、Backbone.js自体に標準搭載されているわけではなく、一番シンプルなのは、Underscore.jsのテンプレート機能を利用することらしい。簡単そうなので、後で調べる。次にルーター機能について確認したいと思います。

ルーター

var MyRouter = Backbone.Router.extend({
    routes: {
        'hoge': 'hoge',
        'aiu': 'aiueo'
    },

    hoge: function(){
        console.log('hogehogehoge');
    },

    aiueo: function(){
        console.log('aiueoaiueo');
    }
});

var router = new MyRouter();
Backbone.history.start();

こんな感じでつくる。ということは、まずルーターのroutesがURLを検証して、何かに合致したら該当する関数を呼出すところからアプリケーションが始まるわけであります。そこから、viewを作って、そこで色々モデルを使いながら表示する内容をつくって、テンプレートに渡して表示するわけであります。実際的にはViewは、cakePHPのレイアウトとか、view、エレメントとかに分けて作成してそれを組み合わせていくわけであります。

Marionette

http://marionettejs.com/ Backbone.jsのコードをよりシンプルに、管理し易くしてくれるやつらしい。Backbone.js使うなら使った方がいいらしい。

参考: Marionette.jsまとめ その1 Application, Controller, AppRouter 実践Backbone.Marionette 現場の悩みと解決まで "Backbone.Marionette.js: A Gentle Introduction" を今更ながら勉強してみた

上記3つを見ると色々分かりそうだなーと思いました。ありたがいです。