勉強会JS編＜6＞ yeoman + backbone.view


## 関連記事

* [勉強会JS編＜1＞ オブジェクト指向言語としてのJavaScriptを理解](http://qiita.com/park-jh/items/1887d87f33474cf7d733)
* [勉強会JS編＜2＞ クライアントサイドMVCフレームワーク](http://qiita.com/park-jh/items/8b0a21e09223e3a8d0bc)
* [勉強会JS編＜3＞ フロントエンド開発環境構築](http://qiita.com/park-jh/items/319cacc28850c9fd4898)
* [勉強会JS編＜4＞ yeoman + backbone.model + grunt](http://qiita.com/park-jh/items/78bc01b93fe6d4167624)
* [勉強会JS編＜5＞ yeoman + backbone.collection + backbone.localStorage](http://qiita.com/park-jh/items/49fefe30cdf57de7b6f0)
* 勉強会JS編＜6＞ yeoman + backbone.view
* [勉強会JS編＜7＞ yeoman + backbone.router](http://qiita.com/park-jh/items/8f7d4275279201d5796b)
* [勉強会JS編＜8＞ yeoman + backbone.js 実践 - その１](http://qiita.com/park-jh/items/bad19e1c6b502ef0d0fa) 
* [勉強会JS編＜9＞ yeoman + backbone.js 実践 - その２](http://qiita.com/park-jh/items/55d62bc58b94b12835c3)

## Backbone.Viewとは

* HTMLテンプレートと組み合わせてモデルが持つデータを画面に表示する。
* データの更新を受けて画面の表示を更新する。
* DOM上のイベントを受けてモデルを更新する。

## 実習

### オブジェクトの定義

* yeomanでBackbone.Viewの雛形を生成する。

```zsh
  [devnote@hooni:~/Documents/study/js/sample] % yo backbone:view contact
     create app/scripts/templates/contact.ejs
     create app/scripts/views/contact.js
     create test/views/contact.spec.js
```

* 生成されたビューを下記のように修正する。
  - テンプレートエンジンとしてejsを使っていることに注目
  - ビューの生成の確認ためinitialize()の中にログ用のメッセージを追加
  - render()の中には最後に自身の参照を返すように「return this;」を追加

```javascript
  // app/scripts/views/contact.js
  /*global Sample, Backbone, JST*/

  Sample.Views = Sample.Views || {};

  (function () {
    'use strict';

    Sample.Views.Contact = Backbone.View.extend({

      template: JST['app/scripts/templates/contact.ejs'],

      tagName: 'div',

      id: '',

      className: '',

      events: {},

      initialize: function () {
        console.log('Viewが初期化されました。');
        this.listenTo(this.model, 'change', this.render);
      },

      render: function () {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
      }

    });

  })();
```

* el
  - Backbone.Viewのインスタンスが管理するDOM要素の最上位のルート要素
  - ビューオブジェクトの中に定義されていない又は初期化のときelオプションが渡されない場合は、Backbone.Viewが内部で自動的に生成する。
  - elプロパティに新しいDOM要素が生成されるときtagNameの指定がない場合は、生成されるDOM要素をdivタグでラップする。

* $el 
  - elプロパティをjQueryオブジェクト化したもの
  - elプロパティが設定される際に一緒に保持される。

* tagName
  - 指定されたタグ名で生成されるDOM要素をラップする。

* attributes
  - DOMの属性と値をオブジェクト形式で指定できる。

* className
  - class属性を指定する。

* id
  - id属性を指定する。

* template()
  - underscore.jsから提供されているメソッド
  - テンプレートにモデルオブジェクトの内容をバインドしてくれる。

* html()
  - jQueryから提供されるメソッド
  - 指定した要素に引数で渡された値をセットする。

### モデルのデータの表示

* yeomanで生成されたテンプレートを下記のように修正する。

```javascript
  <p>Your content here.</p> // 最初生成された雛形にはこれしかない。
  <div>name: <%= firstname %> <%= lastname %></div>
  <div>email: <%= email %></div>
```

* モデルとビューを生成

```javascript
  // app/scripts/main.js
  ...snip...

  init: function () {
    'use strict';
    console.log('Hello from Backbone!');

    // モデルの初期化
    var contact = new Sample.Models.Contact({
      firstname: '太郎',
      lastname: '山田',
      email: 'yamada@example.com'
    });
    return contact;
  },

  ...snip...

  view_ex01: function(contact) {
    var contactView = new Sample.Views.Contact({
      model: contact
    });
    console.log(contactView.el);

    return contactView;
  },

  ...snip...

  $(document).ready(function () {
    'use strict';
    var c = Sample.init();
    var v = Sample.view_ex01(c);
    v.render().$el.appendTo($(document.body));
  });
```

* appendTo()
  - jQueryから提供されるメソッド
  - $(A).appendTo(B)はBにAが追加されることだから、トップページのbodyコンテンツの最後にビューのテンプレートが表示されるわけ

* トップ画面の一番下にテンプレートの内容が表示される。

```
  Your content here.

  name: 太郎 山田
  email: yamada@example.com
```

* developer toolsのconsoleにてelプロパティを確認する。

```html
  <div>
    <p>Your content here.</p>
    <div>name: 太郎 山田</div>
    <div>email: yamada@example.com</div>
  </div>
```

### プロパティを設定

* ビューを下記のように修正する。

```javascript
  // app/scripts/views/contact.js
  ...snip...

  template: JST['app/scripts/templates/contact.ejs'],

  tagName: 'p',

  id: function() {
    return 'contact-' + this.model.get('id');
  },

  className: 'contact',

  attributes: {
    'data-attribute': 'someData',
    'data-other-attribute': 'otherData'
  },

  ...snip...
```

* developer toolsのconsoleにてelプロパティを確認する。
  - divタグの代わりにpタグでラップされている。
  - attributesに設定した属性とid、classが表示される。
  - モデルオブジェクトの中にid属性がないため、id="contact-undefined"と表示される。

```html
  <p data-attribute="someData" data-other-attribute="otherData" id="contact-undefined" class="contact"><p>Your content here.</p>
  <div>name: 太郎 山田</div>
  <div>email: yamada@example.com</div>
  </p>
```

### イベント

* ビューのテンプレートにイベントを発火するチェックボックスを追加する。

```html
  <input class="toggle" type="checkbox"><span>メールの受信に同意します。</span>
```

* ビューにイベントを登録する。

```javascript
  // app/scripts/views/contact.js
  events: {
    // '.toggle'セレクタで特定できる要素のクリックイベントを監視してtoggleCompleted()メソッドを呼び出す。
    // 内部ではthis.$el.on()が実行されている。
    'click .toggle':'toggleCompleted'
  },

  toggleCompleted: function(e) {
    // jQueryのしくみで動いているので引数eはjQueryのイベントオブジェクトを参照している。
    console.log('チェックボックスがクリックされました。');
    // コールバック関数のthisは現在のビューインスタンスを指す。
    console.log(this instanceof Sample.Views.Contact);
  },
```

* developer toolsのconsoleにてチェックボックスをクリックするときメッセージが出力される。

```
  チェックボックスがクリックされました。
  contact.js:35 true
```

## 参考書籍

* JavaScriptエンジニア養成読本