问题
I have an app which uses both Backbone and Handlebars on a server and a client.
Server
Backbone and Express-Handlebars installed
app.js
app.set('views', path.join(__dirname, '/views'));
app.engine('.hbs', expHbs({
defaultLayout: 'index',
extname: '.hbs'
}));
app.set('view engine', '.hbs');
index.js
exports.init = function(req, res){
res.render('contact/index');
};
index.hbs
<div class="row">
<div class="col-sm-6">
<div class="page-header">
<h1>Send A Message</h1>
</div>
<div id="contact"></div>
</div>
....some code
<script id="tmpl-contact" type="text/x-handlebars-template">
<form>
bootstrap with handlebars temlates {{....}} in here
</form>
</script>
Client
On the client I have Backbone and Handlebars installed via Bower
In index.js Backbone.view
var Handlebars = require('handlebars');
app.ContactView = Backbone.View.extend({
el: '#contact',
template: Handlebars.compile( $('#tmpl-contact').html() ),
events: {
'submit form': 'preventSubmit',
'click .btn-contact': 'contact'
},
initialize: function() {
this.model = new app.Contact();
this.listenTo(this.model, 'sync', this.render);
this.render();
},
render: function() {
this.$el.html(this.template( this.model.attributes ));
this.$el.find('[name="name"]').focus();
},
preventSubmit: function(event) {
event.preventDefault();
},
contact: function() {
this.$el.find('.btn-contact').attr('disabled', true);
this.model.save({
name: this.$el.find('[name="name"]').val(),
email: this.$el.find('[name="email"]').val(),
message: this.$el.find('[name="message"]').val()
});
}
});
What happens is that index.hbs renders on the server-side normally, but it is not rendering a form inside script; it shows empty <div id="contact"></div>
and doesn't shows any errors in console.
As shown here Using Handlebars with Backbone, a way to replace underscore templating with handlebars is simply to replace _.template
with Handlebars.compile
, but neither of these options works for me. I also tried different type attributes for <script>
and it's still not working.
How can I fix this? Any help is appreciated. Thanks.
Added full index.js on client
/* global app:true */
var Handlebars = require('Нandlebars');
(function() {
'use strict';
app = app || {};
app.Contact = Backbone.Model.extend({
url: '/contact/',
defaults: {
success: false,
errors: [],
errfor: {},
name: '',
email: '',
message: ''
}
});
app.ContactView = Backbone.View.extend({
el: '#contact',
template: Handlebars.compile( $('#tmpl-contact').html() ),
events: {
'submit form': 'preventSubmit',
'click .btn-contact': 'contact'
},
initialize: function() {
this.model = new app.Contact();
this.listenTo(this.model, 'sync', this.render);
this.render();
},
render: function() {
this.$el.html(this.template( this.model.attributes ));
this.$el.find('[name="name"]').focus();
},
preventSubmit: function(event) {
event.preventDefault();
},
contact: function() {
this.$el.find('.btn-contact').attr('disabled', true);
this.model.save({
name: this.$el.find('[name="name"]').val(),
email: this.$el.find('[name="email"]').val(),
message: this.$el.find('[name="message"]').val()
});
}
});
$(document).ready(function() {
app.contactView = new app.ContactView();
});
}());
回答1:
So as mentioned here Handlebars.compile
must load after handlebars template in <script></script>
is loaded into the DOM. In this case when using express-hanldebars, a link to js file must be placed after {{{ body }}}
element in the main layout. That is the right answer.
There is one more problem here that app
can't be defined globally as it appears in index.js
In order to define app
globally you have to move app = app || {};
outside the IIFE scope and put it at the beginning of a file and declare it as a global variable: var app = app || {};
. If there are multiple backbone files they should all implement a similar structure in order to app
be global.
来源:https://stackoverflow.com/questions/42335681/handlebars-with-backbone-template-not-rendering