Underscore.js模板问题 - 无法调用null的方法'replace'

时间:2012-06-12 17:07:07

标签: backbone.js underscore.js

我一直在寻找并找到了很多答案,但似乎都没有。

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>
           Shopping Cart
        </title>
        <link rel="stylesheet" href="lib/style.css" type="text/css">
    </head>
    <body>
<script id="rtemp" type="text/x-underscore-template"">
            <span><%= title %></span>
    </script>
        <script src="lib/jquery.js" type="text/javascript"></script>
        <script src="lib/underscore.js" type="text/javascript"></script>
        <script src="lib/backbone.js" type="text/javascript"></script>
        <script src="lib/script.js" type="text/javascript"></script>
    </body>
    <script>
var Photo = Backbone.Model.extend({


    initialize: function(){
        console.log('this model has been initialized');

        this.bind("change:title", function(){
            var title = this.get("title");
            console.log("My title has been changed to.. " + title);
            var pv = new PhotoView();
            pv.render();
        });

    },

    setTitle: function(newTitle){
        this.set({ title: newTitle });
    },

    setLocation: function(newLoc)
    {
        this.set({location:newLoc});
    }
});

var PhotoView = Backbone.View.extend
({
    el: $('body'),

    render: function(event)
    {
        var name = myPhoto.get('title');
        console.info(name);
        var template = _.template($('#rtemp').html(), {title:name});
        console.info(this.model);
        $(this.el).html(template);
        return this;
    }

});



    </script>
</html>

首先;

创建方法的新实例

 var newPhoto = new Photo();
 newPhoto.setTitle('Fishing');

这项工作很好,它会通过模板加载到身体。但是,如果我再这样做,

newPhoto.setTitle('Sailing');

我收到错误 - “无法调用方法'替换'null'

没有线路错误,但我相信它在

var template = _.template($('#rtemp').html(), {title:name});

1 个答案:

答案 0 :(得分:23)

这里有一些问题。

  1. 您的模板在"属性中有两个type,它应该是:

    <script id="rtemp" type="text/x-underscore-template">
    
  2. 您的观看次数render引用myPhoto时应为this.model

    var name = this.model.get('title');
    
  3. 您的主要问题是,您的视图使用<body>作为this.el,而您的模板位于<body>内。

  4. 在渲染视图时,您完全替换<body>的内容:

    $(this.el).html(template);
    

    所以在第一次render通话后,不再有#rtemp。然后,在下一个render电话中,您可以尝试:

    var template = _.template($('#rtemp').html(), ...);
    

    但由于#rtemp不再存在于DOM中,所以一切都崩溃了。

    如果您立即抓取模板:

    var PhotoView = Backbone.View.extend({
        el: $('body'),
        template: _.template($('#rtemp').html()),
        //...
    });
    

    然后在this.template()中使用render

    render: function(event) {
        //...
        var template = this.template({
            title: name
        });
        //...
    }
    
    你会有更好的运气。当然,您需要确保使用此方法在文档就绪处理程序中定义视图,或者在定义视图时#rtemp可能不可用。

    演示:http://jsfiddle.net/ambiguous/dwGsM/


    那就是说,你的应用程序结构相当奇怪。你有一个模型可以监听自己,然后模型创建并在某些内容发生变化时呈现视图。听自己的模型本身就很好,但通常你会听到模型的视图,当模型发生变化时,视图会重新渲染(或者只是部分)。

    您的模型看起来应该更像这样:

    var Photo = Backbone.Model.extend({
        setTitle: function(newTitle) {
            this.set({ title: newTitle });
        },
        setLocation: function(newLoc) {
            this.set({ location: newLoc });
        }
    });
    

    然后你的观点如下:

    var PhotoView = Backbone.View.extend({
        el: $('body'),
        template: _.template($('#rtemp').html()),
        initialize: function() {
            _.bindAll(this, 'render');
            this.model.on('change:title', this.render);
        },
        render: function(event) {
            this.$el.html(
                this.template(this.model.toJSON())
            );
            return this;
        }
    });
    

    _.bindAll中的initialize可确保使用右this.render调用this;然后initialize绑定到事件,以便它可以响应模型中的更改。视图知道它关心什么,因此它负责处理模型中的更改。在render中,您通常只需调用toJSON即可获取模板的数据。此外,较新版本的Backbone在视图中包含$(this.el)的缓存版本this.$el,因此您不必再自己$(this.el)

    然后你就这样开始了:

    var newPhoto = new Photo();
    var viewPhoto = new PhotoView({ model: newPhoto });
    newPhoto.setTitle('Fishing');
    newPhoto.setTitle('Sailing');
    

    通过在创建视图时指定model选项,告诉视图要使用的模型。

    您可能还想将模板<script>移出<body>

    新的和改进的演示:http://jsfiddle.net/ambiguous/Kytw7/