Underscore.js模板问题 - 无法调用空的“替换” [英] Underscore.js Template Issue - Cannot call method 'replace' of null
问题描述
我一直在找过去,发现答案很多,但没有一个似乎工作。
< HTML的xmlns =http://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(){标题:姓名});
您有几件事错在这里。
-
您的模板具有双重
在
键入
属性,它应该是:<脚本ID =RTEMP类型=文/ X-下划线模板>
-
您视图的
渲染
正在引用myPhoto
当它应该是这一点。模型
:变数名称= this.model.get('标题');
-
和您的主要问题是,您认为使用
<身体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.
Your template has a double
"
in thetype
attribute, it should be:<script id="rtemp" type="text/x-underscore-template">
Your view's
render
is referencingmyPhoto
when it should bethis.model
:var name = this.model.get('title');
And your main problem is that your view uses
<body>
as itsthis.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屋!