我想要实现的是在表单更改时,应该重新呈现整个视图。这是为了提供刚刚编辑过的数据的预览,并在勾选复选框时隐藏表单中的某些元素。
当用户编辑该字段并单击该按钮而不离开该字段时,前两个事件同时被触发:更改,单击。更改处理程序首先更新模型,从而触发重新呈现表单。当点击事件发生时,没有任何反应。我想这与重新渲染有关,因为当我注释掉
时@model.on 'change', @render, @
两个事件处理程序都按原样执行。
可能没有执行点击处理程序,因为已从dom中删除了点击目标并添加了新按钮?我该如何解决这个问题?我在想我写的代码是'惯用'Backbone.js,但我还在学习: - )
以下是我的代码的简化版本,显示了问题: jsbin
答案 0 :(得分:2)
让我们添加一些内容,以便我们可以看到正在发生的事情。首先,我们将使用唯一ID标记保存按钮:
render: ->
id = "b#{Math.floor(Math.random() * 1000)}"
console.log('button id = ', id)
#...
然后我们可以看到哪个按钮被击中:
save: ->
console.log('pressed = ', @$('button').attr('id'))
#...
我们还会添加一个全局点击处理程序来观看Backbone之外的<button>
:
$(document).on('click', 'button', ->
console.log('global click = ', @id)
)
实时版:http://jsbin.com/oviruz/6/edit
稍微使用该版本,您可能会看到发生了什么:
<input>
。<input>
失去焦点,就会触发更改事件。
fieldChanged
@model.set(...)
。@model.set
调用会触发Backbone的事件,尤其是视图@model.on(...)
中的initialize
。render
,其中@$el.html(...)
会替换<input>
和<button>
。html
调用会杀死视图el
中的所有DOM元素。但是,这是一个很大的但是,浏览器需要在此过程完成之前再次获得控制权。<button>
是一个僵尸,因为浏览器的工作队列如下所示:处理点击事件,从 3.4 替换DOM元素。此处 3.4 的工作尚未完成,因此您点击的<button>
是DOM中的一半而且已经半死,并且不会响应任何事件。你有两个事件队列互相争斗;你的Backbone事件正在改变浏览器背后的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
如果您在保存按钮的回调中执行了@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())
答案 1 :(得分:0)
您可以在fieldChange
中的更新模型之前添加一点延迟,您可以将change
事件替换为keyup
。可能有许多变通方法,但最好的方法是不要重新渲染模型更改的整个视图。