はじめに
正確にはjQuery - タグ・エディターを作ってみた - Qiitaで作ったjQueryプラグインをBackbone.jsに移植してみました。
ビューの分割方法
ビューの分割方法に悩みましたが、なるべく単純にしようと思い、タグ1つを表示するTagItemViewとタグ・エディターのTagEditorViewの2つだけとしました。
タグを複数表示するTagCollectionViewを作って、タグエディターはそれを含むcompositeなビューにするのかとか、テキストの幅を測るために画面外においているinput要素とか、タグ入力に使うinput要素もビューにするのか、などと検討しましたが、複雑になる割にメリットが無いので止めました。
モデル
タグ1つを表すTagと複数のタグを表すTagsというコレクションの2つとしました。単に文字列の配列とかでもいいのではと思ったりもしたのですが、下記のモデルの変更イベントを取るためにはBackbone.jsのModelやCollectionであるほうがいいので、そうしました。
モデル変更のイベントでビュー更新
MVCということで、ビューでタグを追加・削除したときのイベント処理はTagsのコレクションにタグを追加・削除するだけとし、Tagsのコレクションの追加・削除イベントでビューの描画を更新するようにしました。
Tagsのコレクションの追加・削除イベントをリッスンするのは以下のコードで、
this.listenTo(this.collection, 'add', this.onAddModel);
this.listenTo(this.collection, 'remove', this.onRemoveModel);
それらのイベントハンドラは以下のコードで実装しています。
onAddModel: function(model, collection, options) {
this.$el.children('div:nth-child(' + (options.at + 1) + ')').after(
new TagItemView({model: model}).render().el);
},
onRemoveModel: function(model, collection, options) {
this.itemViews.splice(options.index, 1);
},
addイベントではoptions.atに何番目に追加されたかが入っていて(Collection#addメソッドのマニュアル参照)、removeイベントではoptions.indexに何番目から削除されたかが入っている(Collection#removeメソッドのマニュアル参照)ので、上記のような実装になっています。
また、タグ1つの内容が変更された場合にTagItemViewを更新するようにもしてあります。
this.listenTo(this.model, 'change', this.render);
タグ・エディターの操作ではこのイベントは起きないのですが、モデルを直接変更した場合に対応するため実装してあります。具体的にはタグのコレクションの変数tagsを以下のように操作すればこのイベントが発生します。
tags.get(1).set('name', 'baz')