meteor.js项目中的铁路由器错误,旧模板的数据被重新调用

时间:2014-09-09 16:43:46

标签: meteor iron-router

我正在开发一个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"
});
});

1 个答案:

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