Underscore.js模板问题 - 无法调用空的“替换” [英] Underscore.js Template Issue - Cannot call method 'replace' of null

查看:74
本文介绍了Underscore.js模板问题 - 无法调用空的“替换”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在找过去,发现答案很多,但没有一个似乎工作。

 < HTML的xmlns =htt​​p://www.w3.org/1999/xhtml>
    < HEAD>
        <标题>
           购物车
        < /标题>
        <链接rel =stylesheet属性HREF =LIB / style.css文件类型=文/ CSS>
    < /头>
    <身体GT;
<脚本ID =RTEMP类型=文/ X-下划线模板>
            <跨度><%=标题%GT;< / SPAN>
    < / SCRIPT>
        <脚本SRC =LIB / jquery.js和类型=文/ JavaScript的>< / SCRIPT>
        <脚本SRC =LIB / underscore.js类型=文/ JavaScript的>< / SCRIPT>
        <脚本SRC =LIB / Backbone.js的TYPE =文/ JavaScript的>< / SCRIPT>
        <脚本SRC =LIB /的script.js类型=文/ JavaScript的>< / SCRIPT>
    < /身体GT;
    <脚本>
变种照片= Backbone.Model.extend({
    初始化:功能(){
        的console.log('这一模式已被初始化');        this.bind(变化:称号功能(){
            VAR标题= this.get(标题);
            的console.log(我的标题已改为..+称号);
            变种PV =新的PhotoView();
            pv.render();
        });    },    的setTitle:功能(newTitle的){
        this.set({标题:newTitle的});
    },    的setLocation:功能(newLoc)
    {
        this.set({位置:newLoc});
    }
});VAR的PhotoView = Backbone.View.extend
({
    EL:$('身体'),    渲染:函数(事件)
    {
        变种名称= myPhoto.get('标题');
        console.info(名);
        VAR模板= _.template($('#RTEMP')HTML(){标题:姓名});
        console.info(this.model);
        $(this.el)的.html(模板);
        返回此;
    }});    < / SCRIPT>
< / HTML>

第一;

创建的方法的一个新实例

  VAR newPhoto =新的Photo();
 newPhoto.setTitle('钓鱼');

这做工精细,它会通过模板加载到体内。但是,如果我那么做一遍,

  newPhoto.setTitle('帆船');

我得到的错误 - 不能调用方法'取代'空的

没有行的错误,但我相信这是在

  VAR模板= _.template($('#RTEMP')HTML(){标题:姓名});


解决方案

您有几件事错在这里。


  1. 您的模板具有双重键入属性,它应该是:

     <脚本ID =RTEMP类型=文/ X-下划线模板>


  2. 您视图的渲染正在引用 myPhoto 当它应该是这一点。模型

     变数名称= this.model.get('标题');


  3. 和您的主要问题是,您认为使用<身体GT; this.el 和你的模板是在<车身方式>


您完全替代的含量<身体GT; 当你渲染视图:

  $(this.el)的.html(模板);

所以第一个渲染电话后,没有更多的 #rtemp 。然后,在接下来的渲染呼叫,您试试这个:

  VAR模板= _.template($('#RTEMP')HTML(),...。);

但因为 #rtemp 不在DOM了,一切都分崩离析。

如果你马上抢模板:

  VAR的PhotoView = Backbone.View.extend({
    EL:$('身体'),
    模板:_.template($('#RTEMP')HTML()。)
    // ...
});

然后用 this.template()渲染

 渲染:函数(事件){
    // ...
    VAR模板= this.template({
        标题:姓名
    });
    // ...
}

你有更好的运气。你会,当然,需要确保你使用这种方法或定义文件准备处理程序中的视图 #rtemp 您可以在定义视图可能无法使用。

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


这是说,你的应用程序的结构是相当奇特。你有听本身,然后将模型创建,当有新的变化呈现一个视图模型。模型听自己本身不错,但通常你可以欣赏聆听模型和视图会重新渲染本身(或只是自己的一部分)作为模型的变化。

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

  VAR照片= Backbone.Model.extend({
    的setTitle:功能(newTitle的){
        this.set({标题:newTitle的});
    },
    的setLocation:功能(newLoc){
        this.set({位置:newLoc});
    }
});

然后你的看法是这样的:

  VAR的PhotoView = Backbone.View.extend({
    EL:$('身体'),
    模板:_.template($('#RTEMP')HTML()。)
    初始化:功能(){
        _.bindAll(这一点,'渲染');
        this.model.on('的变化:标题',this.render);
    },
    渲染:函数(事件){
        这一点。$ el.html(
            this.template(this.model.toJSON())
        );
        返回此;
    }
});

_。bindAll 中的 初始化 确保 this.render 将正确的被称为这个;那么初始化绑定到事件,以便它可以在模型中的变化。视图知道它在乎所以它是负责处理模型中的更改。而在渲染,你通常只需要调用 的toJSON 获得该模板的数据。此外,骨干的较新版本包括 $(this.el)的缓存版本的视图的 这一点。$埃尔 ,所以你不必 $(这.el)你自己了。

然后,你杀青事情是这样的:

  VAR newPhoto =新的Photo();
VAR viewPhoto =新的PhotoView({模式:newPhoto});
newPhoto.setTitle('钓鱼');
newPhoto.setTitle('帆船');

您告诉视图创建视图时指定模式选项来使用什么型号的。

您可能还需要移动模板<脚本> 出的<车身方式>

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

I have been looking over and found alot of answers but none seem to work.

<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>

First;

Create a new instance of the method

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

This work fine, it will load into the body via the template. However if i then do it again,

newPhoto.setTitle('Sailing');

I get the error - "Cannot call method 'replace' of null"

No line error but I believe it is at

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

解决方案

You have a few things wrong here.

  1. Your template has a double " in the type attribute, it should be:

    <script id="rtemp" type="text/x-underscore-template">
    

  2. Your view's render is referencing myPhoto when it should be this.model:

    var name = this.model.get('title');
    

  3. And your main problem is that your view uses <body> as its this.el and your template is inside <body>.

You completely replace the content of <body> when you render your view:

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

so after the first render call, there is no more #rtemp. Then, on the next render call, you try this:

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

but since #rtemp isn't in the DOM anymore, everything falls apart.

If you grab the template immediately:

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

and then use this.template() in render:

render: function(event) {
    //...
    var template = this.template({
        title: name
    });
    //...
}

you'll have better luck. You will, of course, need to make sure that you define your view inside a document-ready handler with this approach or #rtemp might not be available when you define your view.

Demo: http://jsfiddle.net/ambiguous/dwGsM/


That said, the structure of your application is rather bizarre. You have a model which listens to itself and then the model creates and renders a view when something changes. A model listening to itself is fine in itself but usually you have views listening to models and the view would re-render itself (or just parts of itself) as the model changes.

Your model should look more like this:

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

And then your view like this:

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

The _.bindAll in initialize ensures that this.render will be called with the right this; then initialize binds to the event so that it can respond to changes in the model. The view knows what it cares about so it is responsible for dealing with changes in the model. And in the render, you usually just call toJSON to get the data for the template. Also, newer versions of Backbone include a cached version of $(this.el) in the view as this.$el so you don't have to $(this.el) yourself anymore.

Then you'd crank things up like this:

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

You tell the view what model to use by specifying the model option when creating the view.

You might also want to move the template <script> out of <body>.

New and Improved Demo: http://jsfiddle.net/ambiguous/Kytw7/

这篇关于Underscore.js模板问题 - 无法调用空的“替换”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆