Подтвердить что ты не робот

Вызов плагина jQuery в методе рендеринга Backbone

У меня есть метод рендеринга в Backbone, который выглядит в основном следующим образом:

render: function () {
  $.tmpl(this.template, attrs).appendTo(this.el);
  return this;
},

который вызывается из действия маршрутизатора:

action: function () {
  $('#container').empty();
  $('#container').append(myView.render().el);
},

Теперь я хочу применить плагин к элементам label внутри этого представления. Моя первая мысль заключалась в том, чтобы вызвать плагин внутри render:

render: function () {
  $.tmpl(this.template, attrs).appendTo(this.el);
  this.$('label').inFieldLabels();
  return this;
},

но это не работает (я предполагаю, что это потому, что элемент еще не добавлен в DOM). Он работает, если я вызываю плагин в действии маршрутизатора, хотя:

action: function () {
  $('#container').empty();
  $('#container').append(myView.render().el);
  myView.$('label').inFieldLabels();
},

Я бы предпочел не делать этого, потому что плагин является частью представления, а не маршрутизатором, поэтому нет смысла его вызывать внутри действия. Есть ли лучший способ сделать это?

4b9b3361

Ответ 1

Beter делает это следующим образом:

action: function () {
    var container = $('#container');

    container.empty();
    myView.render(container);
},

render: function (container) {
    $(this.el)
        .append($.tmpl(this.template, attrs))
        .appendTo(container);
    $('label', this.el).inFieldLabels();
    return this;
},

Ответ 2

У меня возникла аналогичная проблема с настройкой плагина JQuery Tools Tooltip. Но у меня был совсем другой подход, который хорошо работает: запуск пользовательского события в представлении. Насколько я знаю, в "Багтере" не было введено событие "вставлено в дом", поэтому я просто сделал это сам. Я не использую Router, но измененный код выше выглядел бы примерно так:

// In the router:
action: function () {
    var container = $('#container');

    container.append(myView.render().el));
    myView.trigger('rendered');
},

// In the view:
initialize: function() {
    this.bind('rendered', this.afterRender, this);
},
render: function (container) {
    $(this.el).append($.tmpl(this.template, attrs))
    return this;
},
afterRender: function() {
    $('label', this.el).inFieldLabels();
}

Я полагаю, что преимущество заключается в том, что представление остается неосведомленным о его контейнере. Недостатком является то, что он похож на дополнительную строку или два кода. Но если вам нужно настроить множество плагинов или сделать больше вещей, требующих, чтобы элемент находился в DOM, он будет работать хорошо (и он будет разделять логику).

Мне действительно нравится метод @Skilldrick для передачи контейнера в представление, но я все еще чувствую, что имеет смысл заставить родительское представление отвечать за вставку детей. Я новичок в Backbone, поэтому, пожалуйста, не стесняйтесь комментировать.

Ответ 3

Мне удалось заставить это работать для моего плагина jQuery только, указав контекст для jQuery в функции рендеринга:

    render: function () {
    $(this.el).html(this.template(this.model.toJSON()));
    $('#email1dropdown', this.el).dropdownify();

    return this;
},

Ответ 4

Я решил эту проблему, добавив метод loadPlugins к моему представлению, поэтому я могу сделать myView.loadPlugins() после рендеринга в действии. Это не идеально, но он работает.


Изменить: Хорошо, я слышал от верха лошади, и похоже, что я не могу применить плагин перед тем, как элемент был добавлен в DOM, так что либо я могу сделать, как указано выше (с помощью loadPlugins), либо я могу изменить код, чтобы этот элемент был добавлен в DOM в методе render. Надеюсь, это поможет кому-то в подобном положении.

Вот как я это делаю сейчас:

//in router
action: function () {
  var myView = new MyView({
    el: '#container'
  });
}

//in view
render: function () {
  $.tmpl(this.template, attrs).appendTo(this.el); //this now appends to the DOM
  this.loadPlugins();
  return this;
},

loadPlugins: function () {
  this.$('label').inFieldLabels();
  //and other plugins
},

Ответ 5

У меня возникла аналогичная проблема, но в моем случае даже вышеупомянутые решения не работали, поскольку родительские представления еще не были добавлены в DOM.

Придерживаясь соглашения о наличии родительского представления, добавьте детей в DOM, делая loadPlugins() в методе рендеринга не работает.

Это то, что я сделал. Он чувствует себя взломанным, но может помочь, в зависимости от того, как вы управляете своими представлениями по всей иерархии:

render: function() {
  var self = this;

  setTimeout(function() {
    $(self.el).setupPlugin();
  }, 0);

  return this;
}

Использование setTimeout из 0 позволяет завершить текущий стек вызовов, поэтому к моменту, когда функция тайм-аута вызывается видом и все его родители были добавлены в DOM. (Если вы придерживаетесь упомянутого выше соглашения).