Backbone.jsでToDoアプリをつくる

こんにちわ、95(くごー)です(^o^)
先週ラーメン屋に行きまして、予想以上の量にお腹を壊しました。。その後ゴルフの練習でしたが練習になりませんでした。皆さんも大盛りの誘惑には気を付けましょう!あと、ご一緒した方がラーメンとカレーを同時に食べていましたが超絶相性が良くないようです。ミスターハングリーのキーマカレーとパスタはあうのになぁ。

さて、 現在AngularJSVue.jsReact.jsなど色々なJavaScriptフレームワークがあります。その中でも今回Backbone.jsにスポットを当てたいと思います。個人的に少し触ったりした経緯で以前から興味がありました。

Backbone.jsとは

Backbone.jsJavaScriptMVCフレームワークです。JavaScriptで大規模な開発を行いたいときに向いています。また処理ごとに記述するので開発の分担がしやすいかと思います。

前提

Backbone.jsで簡単なToDoアプリをつくりたいと思います。入力フォームにタスク名を入力して、「タスクの追加」をクリックで追加、「削除」ボタンで削除されるシンプルなつくりです。今回はクライアントのみの実装を想定しています。データ永続化をサーバサイド側で行いたい場合はajaxを使用して行うのがいいかもしれませんね。 以下はイメージ図。
f:id:kugor9595:20150622092344p:plain

事前準備

まずはindex.htmlmain.js(ファイル名任意)を作成してください。今回作成したmain.jsに処理を書いていきます。index.htmlは以下のように書きます。注意点としてはJavaScriptの読み込む順番を以下に従ってください。なお今回使用するjQueryのバージョンは1.11.3です。

<!DOCTYPE html>
<html>
<head>
<meta charset='utf8'>
</head>
<body>

<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script src="js/main.js"></script>
</body>
</html>

ディレクトリ構造

事前準備したファイルを以下のように配置します。
f:id:kugor9595:20150624094530p:plain

実行

今回作成するToDoアプリは「登録フォーム部分(画像赤枠部分)」と「Task一覧部分(画像青枠部分)」で構成されています。
f:id:kugor9595:20150622100632p:plain
上記をイメージするとmain.jsがわかりやすいかと思います。では早速main.jsに記述していきます。

(function() {

///Model
var Task = Backbone.Model.extend({
    //validate
    validate: function(attrs){
        if(_.isEmpty(attrs.title)){
            return 'タスク名が指定されてません';
        }
    },
    initialize: function(){
        this.on('invalid', function(model, error){
            $("#error").html(error);
        })
    }
});

Modelは上記のように記述します。
validateは登録フォーム部分が空でないかチェックしています。_.isEmpty()はunderscore.jsの機能です。initializeでフォーム部分が空の時にエラーをhtmlに渡します。

//main.jsの続き

///Collection
var Tasks = Backbone.Collection.extend({ model: Task });

Collectionは上記のように記述します。modelに対象のモデルを指定します。

//main.jsの続き

///View
//Task一覧部分
var TaskView = Backbone.View.extend({
  //Viewのルート要素を指定します。
    tagName: 'li',
    //削除イベント
    initialize: function(){  
     //「Task一覧部分」でタスクが削除されたときremoveメソッドを起動しています。
        //modelも削除する
        this.model.on('destroy', this.remove, this);
    },
    events: {
     //ルート内のクラス名deleteがclickされたときdestroyメソッドを起動します。
        'click .delete':'destroy'
    },
    destroy: function(){
        if(confirm('削除しますか?')){
            //modelも削除
       //this.modelはViewのインスタンス生成時に指定されるモデルです。
            this.model.destroy();
        }
    },
    remove: function(){
    //$elはViewのルート要素です。
        this.$el.remove();
    },
/*
_.templateはunderscore.js の機能で、画面テンプレートを生成するfunctionを返します。
*/
    template: _.template($('#task-template').html()),
    render: function(){
        //modelをtemplateに渡す
        var template = this.template(this.model.toJSON());
        this.$el.html(template);
        return this;
    }
});


var TasksView = Backbone.View.extend({
    tagName: 'ul',
  //登録フォームでタスクが追加されたらaddNewメソッドを起動しています。
    initialize: function(){
    //this.collectionはインスタンス生成時のCollectionです。
        this.collection.on('add', this.addNew, this);
    },
    addNew: function(task){
        var taskView = new TaskView({model: task});
        this.$el.append(taskView.render().el);
    },
    render: function(){
        this.collection.each(function(task){
            var taskView = new TaskView({model: task});
            this.$el.append(taskView.render().el);
        },this);
        return this;
    }
});

//登録フォーム部分
var AddTaskView = Backbone.View.extend({
  //htmlの要素を指定します
    el: '#addTask',
    events: {
    //submitされたときsubmitメソッドを起動します。
        'submit': 'submit'
    },
    submit: function(e){
        e.preventDefault();
        var task = new Task();
    //titleをModelに設定してvalidateで判定します。
        if(task.set({title: $('#title').val()}, {validate: true})){
       //Collectionに追加
            this.collection.add(task);
        }
    }
});

//インスタンス化
var tasks = new Tasks();
var tasksView = new TasksView({collection: tasks});
var addTaskView = new AddTaskView({collection: tasks});

$('#tasks').html(tasksView.render().el);

})();

index.htmlのbody内に追記。

<!DOCTYPE html>
<html>
<head>
<meta charset='utf8'>
</head>
<body>

<!-- 登録フォーム部分 -->
<form id="addTask">
    <input type="text" id="title">
    <input type="submit" value="タスクを追加">
</form><span id="error"></span>

<!-- Task一覧部分 -->
<div id="tasks"></div>

<!-- Viewで渡した箇所 -->
<script type="text/template" id="task-template">
<%- title %><span class="delete">[削除]</span>
</script>

<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script src="js/main.js"></script>
</body>
</html>

アクセスして以下のようになればOKです。
f:id:kugor9595:20150622162945p:plain

まとめ

ほぼJavaScriptだけでToDoアプリがつくれました。一見すると複雑なコードに見えるかもしれませんが、処理ごとに記述できるのでメンテナンスがしやすいと思います。また導入も比較的簡単で、HTMLファイルもさほど汚さないので導入をしやすいかと思います。JavaScriptが得意な人ならコード記述の制約があまりないのでサクサクJavaScriptで大規模な開発ができますね。

今回はBackbone.jsで簡単なToDoアプリを作成してみました。次回以降でもう少し機能について説明したいと思います。冒頭で紹介したミスターハングリーのキーマカレーとパスタはこちら