与骨干模板的把手没有呈现

时间:2017-02-20 02:47:37

标签: backbone.js handlebars.js express-handlebars

我有一个在服务器和客户端上同时使用Backbone和Handlebars的应用程序。

服务器

安装了Backbone和Express-Handlebars

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>

客户端

在客户端,我通过Bower安装了Backbone和Handlebars

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()
      });
    }
  });

会发生什么情况是index.hbs在服务器端正常呈现,但它不会在脚本中呈现表单;它显示为空<div id="contact"></div>,并且在控制台中没有显示任何错误。

如此处Using Handlebars with Backbone所示,使用把手替换下划线模板的方法只是将_.template替换为Handlebars.compile,但这些选项都不适合我。我还为<script>尝试了不同的类型属性,但它仍无效。

我该如何解决这个问题?任何帮助表示赞赏。感谢。

在客户端

上添加了完整的index.js
/* 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 个答案:

答案 0 :(得分:1)

因为这里提到的Handlebars.compile必须在<script></script>中的把手模板加载到DOM后加载。在这种情况下,当使用express-hanldebars时,必须在主布局中的{{{ body }}}元素之后放置指向js文件的链接。这是正确的答案。

此处还有一个问题是app无法全局定义,因为它出现在 index.js

为了全局定义app,您必须将app = app || {};移到IIFE范围之外,并将其放在文件的开头,并将其声明为全局变量:var app = app || {};。如果有多个骨干文件,它们都应该实现类似的结构,以便app是全局的。