Вызов плагина jQuery в методе рендеринга Backbone - PullRequest
14 голосов
/ 18 августа 2011

У меня есть метод рендеринга в 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();
},

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

Ответы [ 5 ]

5 голосов
/ 25 августа 2011

Я столкнулся с подобной проблемой при настройке плагина jQuery Tools Tooltip.Но у меня был совершенно другой подход, который хорошо работает: запуск пользовательского события в представлении.Насколько я знаю, в Backbone нет встроенного события «вставлено в дом», поэтому я просто сделал это сам.Я не использую Маршрутизатор, но измененный код выше будет выглядеть примерно так:

// 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, поэтому, пожалуйста, не стесняйтесь комментировать.

5 голосов
/ 18 августа 2011

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 голосов
/ 28 сентября 2011

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

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

    return this;
},
0 голосов
/ 22 августа 2011

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

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

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

render: function() {
  var self = this;

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

  return this;
}

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

0 голосов
/ 18 августа 2011

Я «решил» эту проблему, добавив метод 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
},
...