何が起こっているのかを確認できるように、いくつか追加してみましょう。まず、一意の ID で [保存] ボタンをマークします。
render: ->
id = "b#{Math.floor(Math.random() * 1000)}"
console.log('button id = ', id)
#...
そして、どのボタンが押されたかを見ることができます:
save: ->
console.log('pressed = ', @$('button').attr('id'))
#...
<button>
バックボーンの外部を監視するグローバル クリック ハンドラーも追加します。
$(document).on('click', 'button', ->
console.log('global click = ', @id)
)
ライブ版: http://jsbin.com/oviruz/6/edit
そのバージョンを少しいじってみると、何が起こっているかがわかるかもしれません:
- の内容を変更します
<input>
。
- [保存] をクリックしてみてください。
- がフォーカスを失うとすぐに
<input>
、変更イベントがトリガーされます。
- そのイベントは
fieldChanged
を呼び出します@model.set(...)
。
- この
@model.set
呼び出しは、バックボーンのイベント、特に@model.on(...)
ビューのinitialize
.
- Backbone イベントは、と の両方を置き換える
render
を行う に送信します。@$el.html(...)
<input>
<button>
- この
html
呼び出しは、ビューの .xml 内のすべての DOM 要素を削除しますel
。しかし、これは大きな問題ですが、このプロセスが終了する前に、ブラウザーは再び制御を取得する必要があります。
- ここで、イベント キューに戻り、 [保存] のクリックに対処します。しかし、
<button>
ブラウザの作業キューが次のように見えるため、クリックしているのはゾンビです: クリック イベントを処理し、3.4の DOM 要素を置き換えます。ここでは3.4からの作業が完了していないため、<button>
クリックしている は半分が DOM 内にあり、半分が死んでいて、どのイベントにも応答しません。
互いに競合する 2 つのイベント キューがあります。あなたのバックボーン イベントはブラウザの背後で DOM を変更しています。JavaScript はシングル スレッドであるため、ブラウザは失われ、混乱しています。
@$el.html
ブラウザが追いつくまで呼び出しを遅らせた場合:
set_html = =>
@$el.html """
<input type="text" id="text" value="#{@model.get('foo')}"/>
<button class="save" id="#{id}">Save</button>
"""
setTimeout(set_html, 1000) # Go higher if necessary.
期待どおりの動作が得られます。しかし、それはひどく、恐ろしく、厄介で、恥ずべきことです。
これらの DOM 要素でイベントを処理している間に DOM をいじることは危険をはらんでおり、自分自身を傷つける複雑な方法にすぎません。
render
フィールドが変更されたときにフィールドを検証し、ビューをモデルのイベントにバインドする場合は、手動で検証を行い、サイレントコール"change"
を使用する必要があると思います。set
fieldChanged: (e) ->
field = @$(e.currentTarget)
@model.set({ foo: field.val() }, { silent: true })
// @model.validate(@model.attributes) and do something with the return value
[保存] ボタンのコールバックでa を実行する@model.save()
と、サイレントな変更がまとめて検証され、サーバーに送信されます。このようなもの: http://jsbin.com/oviruz/7/edit
@model.set
または、内部をスキップして次fieldChanged
を使用します@model.validate
。
fieldChanged: (e) ->
val = @$(e.currentTarget).val()
// @model.validate(foo: val) and do something with the return value
のすべての設定を残しますsave
:
save: ->
@model.save(foo: @$('#text').val())
このようなもの: http://jsbin.com/oviruz/8/edit