点击事件处理只在Backbone.js的一次工作 [英] Click event handler only working once in Backbone.js

查看:243
本文介绍了点击事件处理只在Backbone.js的一次工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的骨干,并用它与jQuery在Rails的我。在我看来的渲染的方法,我用 delegateEvents 将事件处理程序绑定到按钮的单击事件ID BTN-去。该按钮本身有问题的视图渲染。

I'm new to Backbone and am using it with jQuery in Rails. In my view's render method, I use delegateEvents to bind an event handler to the "click" event of a button with id btn-go. This button is itself rendered by the view in question.

点击按钮存储的形式的值的阵列,并使视图重新呈现。该按钮本身有问题的视图渲染。这工作我第一次按一下按钮,但没有任何反应,第二次,即使观点并正确地重新渲染它的模板。

Clicking the button stores the form's values in an array and causes the view to re-render. This button is itself rendered by the view in question. This works the first time I click the button, but nothing happens the second time, even though the view does correctly re-render its template.

class MyApp.Views.ChainsNew extends Backbone.View

    # @template is defined by a conditional inside render()

    render: (step_number) ->
        window.model = @model
        @step_number = step_number

        @template = if @step_number is 1 then JST['chains/new'] else JST['chains/step']
        $(@el).html(@template())

        @delegateEvents({
            'click #btn-go': 'add_step'
        })
        @

    add_step: ->
        #divide array into arrays of steps before and after step being edited
        steps = @model.get('steps')
        array1 = steps.slice(0, @step_number - 1)
        array2 = steps.slice(@step_number)
        array1.push(@$el.find('textarea').val())
        newArray = array2.concat(array1)

        @model.set({
            steps: newArray
        })

视图的渲染方法是由路由器调用。正如你可以在下面的code看到,路由器听变更在模型上的事件。这将导致它更新URL,这反过来又触发了路由器的方法被调用,它是该方法内的视图的渲染方法终于打电话。

The view's render method is called by the router. As you can see in the code below, the router is listening to the change event on the model. This causes it to update the URL, which in turn triggers the router's step method to be called, and it's within that method that the view's render method is finally called.

class MyApp.Routers.Chains extends Backbone.Router
    routes:
        'chains/new(/)': 'new'
        'chains/new/step/:step_number(/)': 'step'

    initialize: ->
        # Model
        @model = new MyApp.Models.Chain()
        @listenTo(@model, "change", ->
            @goto_step_number @model.get('steps').length + 1
        )

        # Views
        @view_new = new MyApp.Views.ChainsNew({
            model: @model
        })


    step: (url_step_number) ->
        # Before rendering the view, make sure URL & number of steps in model are correctly related
        url_step_number = parseInt url_step_number
        steps_entered = @model.get('steps').length

        if url_step_number > steps_entered + 1
            @goto_step_number steps_entered + 1
        else
            $('#main-container').html(@view_new.render(url_step_number).el)

    new: ->
        @goto_step_number 1

    goto_step_number: (step_number) ->
        @.navigate('chains/new/step/' + step_number, trigger: true)

为什么没有发生任何变化,第二次我点击按钮?我猜测,事件处理程序没有正确绑定到按钮,但我不知道为什么。

Why doesn't anything happen the second time I click the button? I'm guessing that the event handler hasn't been correctly bound to the button, but I have no idea why.

推荐答案

您的问题就在这里:

$('#main-container').html(@view_new.render(url_step_number).el)

从href=\"http://api.jquery.com/html/#html2\" rel=\"nofollow\">精细的手工的

的.html(htmlString)结果
  [...]结果
  当的.html()用于设置元素的含量,这是该元素的任何内容完全被新的内容所取代。此外,jQuery的新内容替换这些元素之前将其他结构如子元素的数据和事件处理程序。

.html( htmlString )
[...]
When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content. Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.

注意的删除其他结构,如数据和事件处理程序的一部分。事件的顺序是这样的:

Note the removes other constructs such as data and event handlers part. The sequence of events goes like this:


  1. 您拨打渲染

  2. 渲染通话 delegateEvents 来附加一个jQuery事件委托给视图的

  3. 您拨打 $ x.html(view.el),但 view.el 已经有这样的jQuery分离所有的事件绑定(包括您刚才添加的 2 ),清除了 $ X ,然后看跌视图.el $ X

  1. You call render.
  2. render calls delegateEvents to attached a jQuery event delegator to the view's el.
  3. You call $x.html(view.el) but view.el is already there so jQuery detaches all the event bindings (including the one you just added in 2), clears out $x, and then puts view.el back into $x.

但是,当 view.el 放回页面上,事件已经走了。这大致相当于你在做什么:

But when view.el is put back on the page, the events are already gone. This is roughly equivalent to what you're doing:

# In the view...
add_step: ->
    re_render(@step_number + 1)

v = new YourView
$('#main-container').append(v.render(1).el)
re_render = (step_number) ->
    $('#main-container').html(v.render(step_number).el)

演示: http://jsfiddle.net/ambiguous/4rJyB/

您需要停止呼叫的.html 所有的时间。当视图是在页面上,你可以简单地告诉它重新呈现自身,这就是所有你需要做的。所以,如果视图已经被渲染一次,以获得其#主容器,你只需要:

You need to stop calling .html all the time. Once the view is on the page, you can simply tell it to re-render itself and that's all you need to do. So, if the view has been rendered once to get its el into #main-container, you just need to:

@view_new.render(url_step_number)

,就是这样。然后,你可以删除 @delegateEvents 呼叫渲染和使用通常的事件地图上查看:

and that's it. Then you can remove the @delegateEvents call from render and use the usual events map on the view:

class MyApp.Views.ChainsNew extends Backbone.View
    events:
        'click #btn-go': 'add_step'
    render: (step_number) ->
        window.model = @model
        @step_number = step_number

        @template = if @step_number is 1 then JST['chains/new'] else JST['chains/step']
        @$el.html(@template())
        @
    #...

这篇关于点击事件处理只在Backbone.js的一次工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆