Meteor Iron 路由器挂钩 运行 多次

Meteor Iron router hooks being run multiple times

编辑: Here is the github repo. And you can test the site 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

我是不是没有正确使用控制器?

在无法看到您定义的使用这些路由控制器的其余代码(例如模板或路由定义)的情况下,我无法准确说明数据函数被多次调用的原因。我怀疑您可能将 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() 函数.有关可为 route/route 控制器定义的所有可用选项的更多信息,请查看 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;
            }
        }
    });

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

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

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

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