Проблема с кликом в Javascript - PullRequest
0 голосов
/ 25 апреля 2011

Итак, я использую Backbone.js, и в одном из моих основных видов я столкнулся с очень странной ошибкой, которую не могу понять, как ее решить.

Вид выглядит как новый макет Twitter. Он получает массив объектов, каждый из которых описывает коллекцию и просматривает элементы, которые действуют на эту коллекцию. Каждая коллекция представлена ​​одной вкладкой в ​​представлении. Метод render () в моем представлении берет этот массив объектов коллекции, очищает DOM-элемент tabContainer, если он еще не пуст, визуализирует вкладки и затем привязывает события к каждой из этих вкладок.

Теперь в моем коде есть метод для визуализации вкладок и метод для последовательного связывания обработчиков щелчков с этими вкладками. Это прекрасно работает при первом выполнении render (), но при последующих вызовах render () обработчики щелчков не привязываются. Вот соответствующий фрагмент кода:

initialize: function() {
  // Context on render(), _addAllTabs and _bindTabEvents is set correctly to 'this'
  _.bindAll(this, 'render', 'openModel', 'closeModel', 'isOpen', 'addAllModels', '_switchTab',
                  'addOneModel', '_addTab', '_removeTab', '_addAllTabs', '_loadCollection', 
                  '_renderControls', '_setCurrentCollection', '_loadModels', '_bindTabEvents');

  this.template = JST['ui/viewer'];
  $(this.el).html(this.template({}));

  // The tabContainer is cached and always available
  this.tabContainer           = this.$("ul.tabs");
  this.collectionContainer    = this.$("#collection_container");
  this.controlsContainer      = this.$("#controls");
  this.showMoreButton         = this.$("#show_more_button");
},

render: function(collections, dashboard) {
  // If _bindTabEvents has been called before, then this.tab exists. I 
  // intentionally destroy this.tabs and all previously bound click handlers.
  if (this.tabs) this.tabContainer.html("");
  if (collections) this.collections = collections;
  if (dashboard) this.$("#dashboard").html(dashboard.render().el);
  // _addAllTabs redraws each of the tabs in my view from scratch using _addTab
  this._addAllTabs();
  // All tabs *are* present in the DOM before my _bindTabEvents function is called
  // However these events are only bound on the first render and not subsequent renders
  this._bindTabEvents();
  var first_tab = this.collections[0].id;
  this.openTab(first_tab);
  return this;
},

openTab: function (collectionId, e) {
  // If I move _bindTabEvents to here, (per my more thorough explanation below)
  // my bug is somehow magically fixed. This makes no friggin sense.
  if (this.isTabOpen(collectionId)) return false;
  this._switchTab(collectionId, e);
},

_addAllTabs: function() {
  _.each(this.collections, this._addTab );
},

_bindTabEvents: function() {
  this.tabs = _.reduce(_.pluck(this.collections, "id"), _.bind(function (tabEvents, collectionId) {
    var tabId = this.$("#" + collectionId + "_tab");
    tabEvents[collectionId] = tabId.click(_.bind(this._switchTab, this, collectionId));
    return tabEvents
  }, this), {});
},

_addTab: function(content) {
  this.tabContainer.append(
    $('<li/>')
      .attr("id", content.id + "_tab")
      .addClass("tab")
      .append($('<span/>')
        .addClass('label')
        .text(content.name)));
  //this._loadCollection(content.id);
  this.bind("tab:" + content.id, this._loadCollection);
  pg.account.bind("change:location", this._loadCollection); // TODO: Should this be here?
},

etc..

Как я уже сказал, метод render () здесь работает, но только в первый раз. Странная часть заключается в том, что если я переместу строку this._bindTabEvents(); и сделаю ее первой строкой метода openTab (), как в следующем фрагменте, то все это прекрасно работает:

openTab: function (collectionId, e) {
  this._bindTabEvents();
  if (this.isTabOpen(collectionId)) return false;
  this._switchTab(collectionId, e);
},

Конечно, эта строка кода не имеет смысла в этом методе, но она заставляет все это работать нормально, что заставляет меня спросить, почему это работает там, но не работает последовательно, вот так:

this._addAllTabs();
this._bindTabEvents();

Это не имеет смысла для меня, так как, это также не работает, если я поставлю это после этой строки:

var first_tab = this.collections[0].id;

хотя это, по сути, то же самое, что и то, что работает в том, что касается порядка выполнения.

Кто-нибудь имеет представление о том, что я делаю неправильно и что я должен делать, чтобы это исправить (с точки зрения как поведения, так и стиля кодирования)?

Ответы [ 2 ]

1 голос
/ 30 апреля 2011

В функции визуализации вашего представления, return this.delegateEvents(); Я думаю, вы теряете привязки событий к вашим визуализациям, и вам нужно восстановить их.

См. Эту ссылку для документации backbone.js для этой функции: backbone.js - DelegateEvents

0 голосов
/ 25 апреля 2011

Когда вы переключаете вкладки, вы не просто показываете / скрываете контент, вы уничтожаете и перестраиваете элемент dom, поэтому вы также уничтожаете привязанные к ним элементы событий. Вот почему события работают только один раз и поэтому добавление _bindTabEvents в рендер работает, потому что вы каждый раз заново присоединяете события.

при выполнении этой строки: this.tabContainer.html(""); poof ... больше нет вкладок и больше нет событий вкладок.

...