我正在开发一个meteor.js应用程序,我遇到了一个奇怪的错误。我在下面写了我的代码,你可以看到我有一个名为groupsmain的模板,它显示了不同组的列表,当我点击其中一个时,我将去groupdetail模板。一切都运行正常,但只有当我通过单击导航栏从组内部详细模板中去groupmain模板时,虽然页面上的一切看起来都不错,但我在控制台中收到此错误。现在我在groupsmain模板中,而不是groupdetail模板,但是它给出了groupdetail模板的子模板正在使用的属性的错误。
Exception in template helper: TypeError: Cannot read property 'photoId' of undefined
at Object.Template.groupdetailgeneral.helpers.imageUrl (http://localhost:3000/client/views/groups/groupdetail/groupdetail_includes/groupdetailgenera l.js?6c735e98e1dbfa1b7514f5e8f58237ea781f3bb6:8:51)
at http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:2610:16
at http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:1602:16
at Spacebars.call (http://localhost:3000/packages/spacebars.js?fa6d15347dd76a8b1464ca3a0d4605598857db91:169:18)
at Spacebars.mustacheImpl (http://localhost:3000/packages/spacebars.js?fa6d15347dd76a8b1464ca3a0d4605598857db91:106:25)
at Object.Spacebars.mustache (http://localhost:3000/packages/spacebars.js?fa6d15347dd76a8b1464ca3a0d4605598857db91:110:39)
at Template.groupdetailgeneral.HTML.IMG.src (http://localhost:3000/client/views/groups/groupdetail/groupdetail_includes/…mplate.groupdetailgeneral.js?7f3022b55bf1958efe4a4a679309ad74d60ef7ea:7:24)
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:2017:12)
at Blaze._HTMLJSExpander.def.visitAttribute (http://localhost:3000/packages/blaze.js? 5ec4e54b22ab2196bcc772669c0619f71666393e:1950:21)
at HTML.TransformingVisitor.def.visitAttributes (http://localhost:3000/packages/htmljs.js?fcf2660be84fbc0c33b97ee8932dbd46612f3566:226:44) debug.js:41
Exception in template helper: TypeError: Cannot read property 'adminId' of undefined
at Object.Template.groupdetailgeneral.helpers.isAdmin (http://localhost:3000/client/views/groups/groupdetail/groupdetail_includes/groupdetailgeneral.js?6c735e98e1dbfa1b7514f5e8f58237ea781f3bb6:20:26)
at http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:2610:16
at http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:1602:16
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?fa6d15347dd76a8b1464ca3a0d4605598857db91:169:18)
at Template.groupdetailgeneral.HTML.DIV.HTML.DIV.HTML.P.Blaze.If.HTML.A.class (http://localhost:3000/client/views/groups/groupdetail/groupdetail_includes/…plate.groupdetailgeneral.js?7f3022b55bf1958efe4a4a679309ad74d60ef7ea:22:22)
at null.<anonymous> (http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:2385:44)
at http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:1787:16
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:2017:12)
at viewAutorun (http://localhost:3000/packages/blaze.js?5ec4e54b22ab2196bcc772669c0619f71666393e:1786:18)
at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:288:36)
这是我的代码。
mainlayout.html
<template name="mainlayout">
{{> yield}}
</template>
MainController.js
MainController=RouteController.extend({ layoutTemplate:"mainlayout"
, onRun:function(){
//SEO stuff
} });
pagelayout.html
<template name="pagelayout">
{{> yield region="navbar"}}
<div class="container">
{{> yield}}
</div>
{{> yield region="footer"}}
</template>
PageController.js
PageController=MainController.extend({
layoutTemplate:"pagelayout",
// specify which templates to render in the regions of the layout
yieldTemplates:{
"navbar":{
to:"navbar"
},
"footer":{
to:"footer"
}
}
});
detaillayout.html
<template name="detaillayout">
{{> yield region="navbar"}}
{{! we do not simply yield over here, we add a sidebar layout}}
<div class="container">
<div class="row">
<div style="float:right;">
{{> yield region="detailmenu"}}
</div>
<div class="col-md-12">
{{> yield}}
</div>
</div>
</div>
{{> yield region="footer"}}
</template>
DetailController.js
DetailController=PageController.extend({
layoutTemplate:"detaillayout",
// don't forget to yield the navbar and footer too, by extending the yieldTemplates
// property from the parent controller
yieldTemplates:_.extend({
"groupdetailmenu":{
to:"detailmenu"
}
},PageController.prototype.yieldTemplates)
});
groupsmain.html
<template name="groupsmain">
<div class="row">
{{#if currentUser}}
{{>groupssearch}}
{{else}}
<h3>To create or join a group, you need to sign in, or sign up.</h3>
{{/if}}
<br/>
<div class="row">
{{>groupslist}}
</div>
</div>
</template>
groupslist.html
<template name="groupslist">
<div class="groups">
{{#each groups}}
{{> groupitem}}
{{/each}}
</div>
</template>
groupitem.html
<template name="groupitem">
<div class="container groupitem">
<div class="media col-md-2">
<figure class="pull-left">
<img class="media-object img-rounded img-responsive img-placeholder groupimage" src="{{imageUrl}}" alt="/home/wedding.jpg" >
</figure>
</div>
<div class="col-md-6 groupitem">
{{#if isMember}}
<h3> <a href="{{pathFor 'groupdetail'}}">{{title}}</a></h3>
{{else}}
<h3 class="list-group-item-heading"> {{title}} </h3>
{{/if}}
<h4 class="list-group-item-text">
{{desc}}
</h4>
</div>
<div class="col-md-3 text-center pull-right">
<h2> {{numberofmembers}} <small> members </small></h2>
{{#if currentUser}}
{{#if isMember}}
<a href="" class="exit btn btn-danger">Exit</a>
{{else}}
<a href="" class="join btn btn-primary">Join</a>
{{/if}}
{{/if}}
{{#if isAdmin}}<a class="edit" href="{{pathFor 'editgroup'}}">Edit</a>{{/if}}
</div>
</div>
</template>
groupitem.js
Template.groupitem.helpers({
numberofmembers: function() {
return this.members.length;
},
isMember: function() {
return (-1<($.inArray(Meteor.userId(), this.members))? 1 : 0);
},
isAdmin: function() {
return this.adminId == Meteor.userId();
},
imageUrl: function () {
var image =Images.findOne({_id: this.photoId});
if(image==null){
return "/home/noimage.jpg";
}
else
{
return image.url();
}
},
desc: function(){
if(this.description.length > 150)
return this.description.substring(0, 150) + "...";
else
return this.description;
}
});
Template.groupitem.events({
'click .join': function(e) {
e.preventDefault();
Groups.update({
_id: this._id
}, {
$addToSet: {members: Meteor.user()._id}
});
var timelinedata = {
type: "newuser",
description: Meteor.user().username + " joined to the group",
groupid: this._id
};
Meteor.call('createtimeline', timelinedata, function(error, timelineid) {
if (error) {
// display the error to the user
throwError(error.reason);
if (error.error === 302)
console.log('hata')
} else {
}
});
},
'click .exit': function(e) {
e.preventDefault();
Groups.update({
_id: this._id
}, {
$pull: {members: Meteor.user()._id}
});
var timelinedata = {
type: "deleteuser",
description: Meteor.user().username + " exited from the group",
groupid: this._id
};
Meteor.call('createtimeline', timelinedata, function(error, timelineid) {
if (error) {
// display the error to the user
throwError(error.reason);
if (error.error === 302)
console.log('hata')
} else {
}
});
}
});
groupdetail.html
<template name="groupdetail">
<div class="row" id="groupdetail">
<div class="row-fluid">
<div class="col-md-3">
{{>groupdetailgeneral}}
</div>
<div class="container">
<div class="col-md-9 col-lg-9">
{{! {{> timeline}}
</div>
</div>
</div>
groupdetailgeneral.html
<template name="groupdetailgeneral">
<img src="{{imageUrl}}" class="img img-thumbnail img-rounded img-responsive" alt="First slide">
<br/>
<br/>
<div class="panel panel-primary">
<div class="panel-heading">
Group Info
</div>
<div class="panel-body">
<h2>{{this.group.title}}</h2>
<h6>{{this.group.description}}</h6>
<p>
Admin {{this.group.adminName}}
</p>
<p>{{#if isAdmin}}<a class="btn btn-primary edit" href="{{pathFor 'editgroup' _id=this.group._id}}">Edit</a>{{/if}}</p>
</div>
</div>
</template>
groupdetailgeneral.js
Template.groupdetailgeneral.helpers({
imageUrl: function () {
var image =Images.findOne({_id: this.group.photoId});
if(image==null){
return "/home/noimage.jpg";
}
else
{
return image.url();
}
},
isAdmin: function() {
return this.group.adminId == Meteor.userId();
}
});
router.js中的GroupDetailController.js
GroupDetailController=DetailController.extend({
template:"groupdetail",
yieldTemplates:_.extend({
"groupdetailmenu":{
to:"detailmenu"
}
},DetailController.prototype.yieldTemplates),
waitOn: function() {
return[
Meteor.subscribe('singleGroup', this.params._id),
Meteor.subscribe('timelinedata')
]
},
group: function () {
return Groups.findOne(this.params._id);
},
data: function() {
return {
group: this.group()
};
},
onBeforeAction: function (pause) {
if (! Meteor.user()) {
if (Meteor.loggingIn()){}
else
this.render('accessDenied');
pause();
}
}
});
router.js
Router.map(function() {
this.route('home', {
path: '/',
layoutTemplate: 'pagelayout',
controller:"PageController"
});
this.route('groupdetail', {
path: '/groupsmain/:_id',
controller: GroupDetailController
});
this.route('groupsmain', {
path: 'groupsmain',
waitOn: function() {
return [Meteor.subscribe('groups')];
},data: function() {
return {
groups: Groups.find()
};
},
layoutTemplate: 'pagelayout',
controller:"PageController"
});
});
答案 0 :(得分:0)
我认为现在Iron Router不会自动等待waitOn
上声明的订阅,所以你要求一个尚未定义的属性(不是从服务器获取的)对象。
在Iron Router 0.7.0上,我通过添加以下内容使路由器等待订阅:
Router.onBeforeAction(function (pause) {
if (!this.ready()) {
this.render('loading');
pause();
}
});
还要确保定义“加载”模板(我不记得IR是否提供了一个)。
供参考,这是一个long discussion on the issue at IR repo。
编辑:其中一个mantainers为下一个版本安排了一个问题来改变waitOn的语义,使其自动化。参考:https://github.com/EventedMind/iron-router/issues/819