Meteor Iron路由器挂钩多次运行

时间:2015-03-12 18:22:19

标签: javascript meteor iron-router

编辑: Here是github回购。您可以测试网站here

在首页上,只需打开浏览器控制台,您就会注意到WaitOndata正在运行两次。如果没有WaitOn,则数据只运行一次。


我通过扩展RouteController并进一步扩展这些控制器来设置我的页面。例如:

    ProfileController = RouteController.extend({
        layoutTemplate: 'UserProfileLayout',
        yieldTemplates: {
            'navBarMain': {to: 'navBarMain'},
            'userNav': {to: 'topUserNav'},
            'profileNav': {to: 'sideProfileNav'}
        },
        // Authentication
        onBeforeAction: function() {
            if(_.isNull(Meteor.user())){
              Router.go(Router.path('login'));
            } else {
                this.next();
            } 
          }
     });

ProfileVerificationsController = ProfileController.extend({
    waitOn: function() {
        console.log("from controller waitOn");
        return Meteor.subscribe('userProfileVerification');
    },

    data: function() {
        // If current user has verified email
        console.log("from controller data start");
        var verifiedEmail = Meteor.user().emails && Meteor.user().emails[0].verified ? Meteor.user().emails[0].address : '';
        var verifiedPhoneNumber = Meteor.user().customVerifications.phoneNumber && Meteor.user().customVerifications.phoneNumber.verified ? Meteor.user().customVerifications.phoneNumber.number : '';

        var data = {
            verifiedEmail: verifiedEmail,
            verifiedPhoneNumber: verifiedPhoneNumber
        };
        console.log("from controller data end");
        return data;
    }
});

在观察客户端的控制台时,钩子似乎正在运行2-3次。而且我之一也会收到错误,因为数据不可用。以下是仅请求页面一次的控制台:

from controller waitOn
profileController.js?966260fd6629d154e38c4d5ad2f98af425311b71:44 from controller data start
debug.js:41 Exception from Tracker recompute function: Cannot read property 'phoneNumber' of undefined
TypeError: Cannot read property 'phoneNumber' of undefined
    at ProfileController.extend.data (http://localhost:3000/lib/router/profileController.js?966260fd6629d154e38c4d5ad2f98af425311b71:46:62)
    at bindData [as _data] (http://localhost:3000/packages/iron_controller.js?b02790701804563eafedb2e68c602154983ade06:226:50)
    at DynamicTemplate.data (http://localhost:3000/packages/iron_dynamic-template.js?d425554c9847e4a80567f8ca55719cd6ae3f2722:219:50)
    at http://localhost:3000/packages/iron_dynamic-template.js?d425554c9847e4a80567f8ca55719cd6ae3f2722:252:25
    at null.<anonymous> (http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:2445:26)
    at http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:1808:16
    at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:2043:12)
    at viewAutorun (http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:1807:18)
    at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?517c8fe8ed6408951a30941e64a5383a7174bcfa:296:36)
    at Tracker.Computation._recompute (http://localhost:3000/packages/tracker.js?517c8fe8ed6408951a30941e64a5383a7174bcfa:310:14)
from controller data start
from controller data end
from controller waitOn
from controller data start
from controller data end

我没有正确使用控制器吗?

1 个答案:

答案 0 :(得分:1)

如果无法看到您定义的使用这些路由控制器的其余代码(例如模板或路由定义),我无法准确地说出多次调用数据函数的原因。我怀疑您可能正在使用具有多个路由的ProfileVerificationsController,在这种情况下,此控制器的data定义将被执行多次,每个路由使用一个路由器。由于data定义是被动的,因此当您浏览应用程序和数据更改时,这可能导致定义的代码重新运行。

至于你的控制器定义,我建议做一些修改,使代码更健壮和防弹。首先,ProfileController定义:

    ProfileController = RouteController.extend({
        layoutTemplate: 'UserProfileLayout',
        yieldRegions: {
            'navBarMain': {to: 'navBarMain'},
            'userNav': {to: 'topUserNav'},
            'profileNav': {to: 'sideProfileNav'}
        },
        onBeforeAction: function() {
            if(!Meteor.user()) {
                Router.go(Router.path('login'));
                this.redirect('login'); // Could do this as well
                this.render('login'); // And possibly this is necessary
            } else {
                this.next();
            }
        }
    });

请注意我更改的第一件事,yieldTemplatesyieldRegions。此拼写错误将阻止使用此路径控制器的模板区域正确填充所需的子模板。其次,在onBeforeAction定义中,我建议不仅使用Underscore检查Meteor.user()对象是否为null,还要检查它是否为undefined同样。我所做的修改将允许您检查Meteor.user()对象的两种状态。最后,除了将拼写错误校正作为指导用户转到login路线的替代建议外,您可以使用this.redirect()this.render()函数代替Router.go()函数。有关可以为路径/路径控制器定义的所有可用选项的其他信息,请选中this

现在为ProfileVerificationsController定义:

    ProfileVerificationsController = ProfileController.extend({
        waitOn: function() {
            return Meteor.subscribe('userProfileVerification');
        },
        data: function() {
            if(this.ready()) {
                var verifiedEmail = Meteor.user().emails && Meteor.user().emails[0].verified ? Meteor.user().emails[0].address : '';
                var verifiedPhoneNumber = Meteor.user().customVerifications.phoneNumber && Meteor.user().customVerifications.phoneNumber.verified ? Meteor.user().customVerifications.phoneNumber.number : '';

                var data = {
                    verifiedEmail: verifiedEmail,
                    verifiedPhoneNumber: verifiedPhoneNumber
                };
                return data;
            }
        }
    });

请注意我更改的一件事,即使用data将控制器的if(this.ready()){}选项中定义的所有代码包装起来。这在使用waitOn选项时非常重要,因为waitOn选项会将一个或多个订阅句柄添加到路由的等待列表中,this.ready()检查仅在所有句柄都返回true时返回true等待名单已准备就绪。确保使用此检查可以防止在为路由构建数据上下文时意外未加载任何数据。有关定义路由/路由控制器订阅的其他信息,请查看this输出。

作为最后的建议,对于onBeforeAction中的ProfileController选项定义,我建议将其移到自己的全局挂钩中,如下所示:

    Router.onBeforeAction(function() {
        if(!Meteor.user()) {
            Router.go(Router.path('login'));
        } else {
            this.next();
        }
    });

在全局挂钩中定义此检查可确保您不必担心将ProfileController添加到所有路由,只是为了确保对所有路由运行此检查。每次访问该路径时,将对每条路线运行检查。但是,这只是一个建议,因为你可能有理由不这样做。我只是想提出建议,因为我确保为我开发的每个Meteor应用程序都提供额外的安全性。