Вызов плагина 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();
},
Я бы предпочел не делать этого, потому что плагин является частью представления, а не маршрутизатором, поэтому нет смысла его вызывать внутри действия. Есть ли лучший способ сделать это?
Ответы
Ответ 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. (Если вы придерживаетесь упомянутого выше соглашения).