我目前正在尝试使用backbone.js加速,我认为最好的方法就是深入了解在线教程和文档。在线教程和示例应用程序非常好,但为了通过知识构建我正在尝试构建我自己的示例网站CRUD应用程序。对于示例,基本上我正在尝试做的是合并两个当前的在线示例/教程。试图更好地理解使用多个模型,集合和视图。
不幸的是,我已经陷入困境......我为长篇大论的解释道歉,但作为一个新手,我试图尽可能地解释这个问题......
我的网站应用示例基于以下教程:
https://github.com/ccoenraets/backbone-cellar/tree/master/bootstrap
查看在线示例:
http://coenraets.org/backbone-cellar/bootstrap/
我能够遵循本教程并拥有该网站的工作版本。现在我希望扩展应用程序以包含更多适合应用程序(backbone.js)结构的页面。如果您查看教程,您会注意到有一个“关于”页面,它只是将静态html模板加载到应用程序中。我想要做的是添加一个显示联系人管理器的新页面。联系人管理员被剥夺了以下教程:
http://net.tutsplus.com/tutorials/javascript-ajax/build-a-contacts-manager-using-backbone-js-part-1/
请注意:此时为了简单起见,我只使用本教程的第1部分。
现在好了解释我在哪里遇到这个问题......首先,我将概述我所做的事情。在应用程序上,我在headerView中添加了一个名为Directory的新链接。在main.js页面上(origianl的例子:https://github.com/ccoenraets/backbone-cellar/blob/master/bootstrap/js/main.js)我添加了如下代码:
var AppRouter = Backbone.Router.extend({
routes: {
"" : "list",
"wines/page/:page" : "list",
"wines/add" : "addWine",
"wines/:id" : "wineDetails",
"about" : "about",
"directory" : "directory"
},
initialize: function () {
this.headerView = new HeaderView();
$('.header').html(this.headerView.el);
},
list: function(page) {
var p = page ? parseInt(page, 10) : 1;
var wineList = new WineCollection();
wineList.fetch({success: function(){
$("#content").html(new WineListView({model: wineList, page: p}).el);
}});
this.headerView.selectMenuItem('home-menu');
},
wineDetails: function (id) {
var wine = new Wine({id: id});
wine.fetch({success: function(){
$("#content").html(new WineView({model: wine}).el);
}});
this.headerView.selectMenuItem();
},
addWine: function() {
var wine = new Wine();
$('#content').html(new WineView({model: wine}).el);
this.headerView.selectMenuItem('add-menu');
},
about: function () {
if (!this.aboutView) {
this.aboutView = new AboutView();
}
$('#content').html(this.aboutView.el);
this.headerView.selectMenuItem('about-menu');
},
directory: function () {
if (!this.directoryView) {
this.directorytView = new DirectoryView();
}
$('#content').html(this.directoryView.el);
this.headerView.selectMenuItem('directory-menu');
}
});
utils.loadTemplate(['HeaderView','WineView','WineListItemView','AboutView','DirectoryView'],function(){ app = new AppRouter(); Backbone.history.start(); });
现在对于目录(Contacts Manger)页面,为了便于说明,我按照教程将模型视图和集合留在单个.js文件上 - 我当然希望将文件分开(进入模型和视图)一旦我得到它的工作。根据教程,联系人管理器(目录)的代码如下:
//demo data
window.contacts = [
{ name: "Contact 1", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
{ name: "Contact 2", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
{ name: "Contact 3", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "friend" },
{ name: "Contact 4", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "colleague" },
{ name: "Contact 5", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" },
{ name: "Contact 6", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "colleague" },
{ name: "Contact 7", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "friend" },
{ name: "Contact 8", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail@me.com", type: "family" }
];
//define product model
window.Contact = Backbone.Model.extend({
defaults: {
photo: "/img/placeholder.png"
}
});
//define directory collection
window.Directory = Backbone.Collection.extend({
model: Contact
});
//define individual contact view
window.ContactView = Backbone.View.extend({
tagName: "article",
className: "contact-container",
template: $("#contactTemplate").html(),
render: function () {
var tmpl = _.template(this.template);
$(this.el).html(tmpl(this.model.toJSON()));
//alert('this model: ' + this.model.toJSON().name);
return this;
}
});
//define master view
window.DirectoryView = Backbone.View.extend({
el: $("#contacts"),
initialize: function () {
this.collection = new Directory(contacts);
this.render();
},
render: function () {
var that = this;
_.each(this.collection.models, function (item) {
that.renderContact(item);
}, this);
},
renderContact: function (item) {
var contactView = new ContactView({
model: item
});
this.$el.append(contactView.render().el);
}
});
我所做的更改只是删除'var'并替换为'window'。适合应用程序的现有结构。例如:
var DirectoryView = Backbone.View.extend({
变为:
window.DirectoryView = Backbone.View.extend({
现在我遇到的问题。我能够获取输出(渲染)html代码的代码来显示模板。
我认为问题在于
//define individual contact view
window.ContactView = Backbone.View.extend({
tagName: "article",
className: "contact-container",
template: $("#contactTemplate").html(),
render: function () {
var tmpl = _.template(this.template);
$(this.el).html(tmpl(this.model.toJSON()));
alert('this model: ' + this.model.toJSON().name);
return this;
}
});
现在我知道正确解析数据,因为'alert'正确输出了名称。我遇到的问题是以下代码行:
var tmpl = _.template(this.template);
抛出以下错误:“未捕获的TypeError:无法调用方法'替换'为null”。
我对如何解决这个问题毫无头绪:(
DirectoryView.html模板代码为:
<div class="row">
<div class="span12">
<div id="contact"></div>
<script id="contactTemplate" type="text/template">
<img src="<%= photo %>" alt="<%= name %>" />
<h1><%= name %><span><%= type %></span></h1>
<div><%= address %></div>
<dl>
<dt>Tel:</dt><dd><%= tel %></dd>
<dt>Email:</dt><dd><a href="mailto:<%= email %>"><%= email %></a></dd>
</dl>
</script>
</div>
我希望我提供了足够的信息。如果还有其他信息,请告诉我。
感谢您一看:)
杰克
答案 0 :(得分:0)
无法调用null的方法'replace'
这意味着在_.template
方法内部,您尝试将replace
调用为null,可能是String。非核心方法看起来像这样(来自annotated source)
_.template = function(text, data, settings) {
settings = _.defaults({}, settings, _.templateSettings);
var matcher = new RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// This is the only place where replace is used
var index = 0;
var source = "__p+='";
// Replace used on variable text
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
// replace used on source that can't be null
source += text.slice(index, offset)
.replace(escaper, function(match) { return '\\' + escapes[match]; });
source +=
escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :
interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :
evaluate ? "';\n" + evaluate + "\n__p+='" : '';
index = offset + match.length;
});
source += "';\n";
因此变量text
必须为null。在您的代码中,text
为this.template
,因此在初始化时必须为null。
您确定在扩展View
以创建ContactView
时,是否在DOM中加载了#contactTemplate
元素?问题必定存在。尝试使用控制台记录this.template以查看它是否真的为空。如果你想在运行任何javascript之前确保加载DOM,请将它们包装在jQuery ready function中。