带有主干模板的车把未渲染

Posted

技术标签:

【中文标题】带有主干模板的车把未渲染【英文标题】:Handlebars with Backbone template not rendering 【发布时间】:2017-07-09 04:59:41 【问题描述】:

我有一个在服务器和客户端上同时使用 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 在服务器端正常渲染,但它没有在脚本内渲染表单;它显示为空的&lt;div id="contact"&gt;&lt;/div&gt;,并且在控制台中没有显示任何错误。

如Using Handlebars with Backbone 所示,用车把替换下划线模板的一种方法是将_.template 替换为Handlebars.compile,但这些选项都不适用于我。我还为 &lt;script&gt; 尝试了不同的 type 属性,但仍然无法正常工作。

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

在客户端添加了完整的 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();
  );
());

【问题讨论】:

你在哪里初始化index.js...中的视图?声明一个视图是不够的。您需要在加载所需的内容后对其进行初始化。 @T J 如果你的意思是使用 Backbone.Model.Extend,我把它放在同一个文件中 (function() 'use strict'; app = app || ; app.Contact = Backbone.Model.extend( url: '/contact/', 默认值: 成功: false, errors: [], errfor: , name: '', email: '', message: '' ); 这是带有 Jade 和 Underscore 模板的 github.com/jedireza/drywall。我正在尝试将其更改为车把。 不,您应该在某处拥有new app.ContactView()。顺便说一句,如果您要共享代码块,请edit 并添加它。它们在 cmets 中是不可读的 $(document).ready(function() app.contactView = new app.ContactView(); ); 将初始化视图然后您的应用程序加载。那时index.hbs 的内容是否可用?还是稍后加载? 【参考方案1】:

所以这里提到Handlebars.compile 必须在&lt;script&gt;&lt;/script&gt; 中的车把模板加载到DOM 之后加载。在这种情况下,使用 express-hanldebars 时,必须在主布局中的 body 元素之后放置指向 js 文件的链接。这是正确的答案。

这里还有一个问题,app 不能像 index.js

中出现的那样在全局范围内定义

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

【讨论】:

以上是关于带有主干模板的车把未渲染的主要内容,如果未能解决你的问题,请参考以下文章

车把或主干将空字符串插入 html

如何从车把模板访问主干模型的计算字段?

如何从车把模板访问主干模型的计算字段?

侧 el 的嵌套 id 中的主干渲染模板

模型属性未统一命名的主干集合和模板

重新初始化主干视图后未触发事件