最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using bootstrap-modal as Backbone.js view - Stack Overflow

programmeradmin0浏览0评论

I am attempting to create a Backbone.js view based on a Twitter bootstrap-modal, which makes use of Backbone's automatic event delegation via the events attribute of the view.

Unfortunately, bootstrap-modal seems to break Backbone's event delegation as it clones the view HTML before displaying the modal:

that.$element
      .appendTo(document.body)
      .show()

My view:

App.Views.ProjectsNav ||= {}

class App.Views.ProjectsNav.NewProjectView extends Backbone.View
  events: {
    'click .save': 'save',
    'shown':       'shown'
  }

  save: (e) ->
    ...
    false

  shown: () ->
    App.Helpers.Forms.setFocus($(@el), true)
    false

  render: () ->
    $(@el).html(ich.nav_edit_project_template(@model.toJSON()))
    @$('.modal').modal({'show': true, 'keyboard': true, 'backdrop': true})
    @

The corresponding (Mustache) HTML template:

<div class="modal hide" style="display: none; ">
  <div class="modal-header">
    <a href="#" class="close">×</a>
    <h3>New Project</h3>
  </div>
  <div class="modal-body form-stacked">
    <label for="name">Name</label> <input type="text" name="name" value="{{name}}"/><input type="hidden" name="lock_version" value="{{lock_version}}"/>
  </div>
  <div class="modal-footer">
    <a href="javascript:void(0)" class="save btn primary">Create</a>
    <a href="javascript:void(0)" class="cancel btn secondary">Cancel</a>
  </div>
</div>

Neither save nor shown are called when the respective events are triggered.

Any ideas?

I am attempting to create a Backbone.js view based on a Twitter bootstrap-modal, which makes use of Backbone's automatic event delegation via the events attribute of the view.

Unfortunately, bootstrap-modal seems to break Backbone's event delegation as it clones the view HTML before displaying the modal:

that.$element
      .appendTo(document.body)
      .show()

My view:

App.Views.ProjectsNav ||= {}

class App.Views.ProjectsNav.NewProjectView extends Backbone.View
  events: {
    'click .save': 'save',
    'shown':       'shown'
  }

  save: (e) ->
    ...
    false

  shown: () ->
    App.Helpers.Forms.setFocus($(@el), true)
    false

  render: () ->
    $(@el).html(ich.nav_edit_project_template(@model.toJSON()))
    @$('.modal').modal({'show': true, 'keyboard': true, 'backdrop': true})
    @

The corresponding (Mustache) HTML template:

<div class="modal hide" style="display: none; ">
  <div class="modal-header">
    <a href="#" class="close">×</a>
    <h3>New Project</h3>
  </div>
  <div class="modal-body form-stacked">
    <label for="name">Name</label> <input type="text" name="name" value="{{name}}"/><input type="hidden" name="lock_version" value="{{lock_version}}"/>
  </div>
  <div class="modal-footer">
    <a href="javascript:void(0)" class="save btn primary">Create</a>
    <a href="javascript:void(0)" class="cancel btn secondary">Cancel</a>
  </div>
</div>

Neither save nor shown are called when the respective events are triggered.

Any ideas?

Share Improve this question asked Jan 10, 2012 at 22:53 Thilo-Alexander GinkelThilo-Alexander Ginkel 6,95810 gold badges47 silver badges58 bronze badges 7
  • Is there an "opened" callback of some sort that you could use to fill the modal with HTML? Basically bypass the cloning (or at least the part of the cloning that is screwing up delegate). – mu is too short Commented Jan 11, 2012 at 5:43
  • Yes, cf. twitter.github.com/bootstrap/1.4.0/bootstrap-modal.js. Unfortunately, the show event is called before the clone (and I am not getting the shown event due to the original problem). – Thilo-Alexander Ginkel Commented Jan 11, 2012 at 15:11
  • What about the shown event? "This event is fired when the modal has been made visible to the user (will wait for css transitions to complete)." – mu is too short Commented Jan 11, 2012 at 20:09
  • Well, as the shown event is fired after the HTML fragment has been moved to another place in the DOM (document.body), the backbone view is not getting its callback invocation (@el is no longer pointing there). – Thilo-Alexander Ginkel Commented Jan 11, 2012 at 20:19
  • Could you create the modal and then put the Backbone view inside it? – mu is too short Commented Jan 11, 2012 at 20:27
 |  Show 2 more comments

1 Answer 1

Reset to default 17

Allright, so the solution is was rather simple:

App.Views.ProjectsNav ||= {}

class App.Views.ProjectsNav.NewProjectView extends Backbone.View
  tagName: 'div'

  events: {
    'click .save':   'save',
    'click .cancel': 'hide',
    'hidden':        'hidden',
    'shown':         'shown'
  }

  initialize: (options) ->
    super(options)
    @collection = options.collection

  hide: () ->
    @el.modal(true).hide()
    false

  save: (e) ->
    ...
    @model.save(attrs, {
      success: (project) =>
        @model = project
        @collection.add(@model)
        @hide()
      error: (project) =>
        alert('Something went wrong: ' + project)
      }
    )
    false

  render: () ->
    @el = ich.nav_edit_project_template(@model.toJSON()).modal('keyboard': true, 'backdrop': true)
    @delegateEvents()
    @el.modal('show': true)
    @

  hidden: () ->
    @remove()
    false

  shown: () ->
    App.Helpers.Forms.setFocus($(@el), true)
    false

Summing things up, the key is to split showing the modal into two steps giving the possibility to assign @el and invoke @delegateEvents() afterwards before making it visible. @el.modal(true) can be used to get access to the object controlling the modal, e.g., to programmatically hide it.

发布评论

评论列表(0)

  1. 暂无评论