问题
I have a Meteor template with multiple conditions, and I get a flicker of some of the conditional views when it loads initially.
I'm using iron router and I'm aware of the subscriptions, wait() and ready() options, however one of the problems is that the main conditional isInstalled
depends on a meteor.call callback to set the isInstalled variable, so the wait doesn't depend on a subscription. So how do I account for this use case?
<template name="adminLayout">
{{#if isInstalled}}
{{#if currentUser}}
{{> adminHeader}}
<br /><br />
<div class="row">
<div class="medium-3 columns">
{{> adminNav}}
</div>
<div class="medium-9 columns">
{{> yield}}
</div>
</div>
<div class="row">
<div class="medium-12 columns">
{{> adminFooter}}
</div>
</div>
{{else}}
{{> login}}
{{/if}}
{{else}}
{{> install}}
{{/if}}
</template>
Here's my Template helper, illustrating how I'm providing the value for isInstalled
Meteor.call('isInstalled', function (err, result) {
if (err) {
console.log(err);
}
Session.set('isInstalled', result);
});
Template.adminLayout.helpers({
isInstalled: function () {
return Session.get('isInstalled');
}
});
And lastly the route:
Router.route('/admin', function () {
this.layout('adminLayout');
this.render('dashboard');
});
回答1:
How about onBeforeAction hook? Of course you would have to have other routes for /login and /install but I think that would be better approach because user should be able to navigate through url, something like:
Router.onBeforeAction(function() {
if (!Meteor.userId()) {
Router.go('/login');
this.next();
} else {
if (/*check somehow if installed*/) {
this.next();
}else{
Router.go('/install');
this.next();
}
}
});
回答2:
As it turns out the flickering issue is really a Meteor issue, not an Iron Router one, though iron router can provide a workaround to solve the problem using its wait() and ready() methods.
In my particular case I didn't require a wait on a subscription but on a Meteor.call result. In order to achieve this I created an anonymous function that return an object handle with a ready method that Iron Router could understand and I could later implement in the route logic.
Sindis guided me in the right direction though it was an incomplete solution. Below is how I accomplished it:
Router.onBeforeAction(function (params) {
var self = this;
if (params.url.match(/admin/)) {
this.wait(function(){
Meteor.call('isInstalled', function (err, result) {
Session.set('installationCheck', true);
Session.set('isInstalled', result);
});
return {
ready: function () {
return Session.get('installationCheck');
self.next();
}
}
});
if (this.ready()) {
if (Session.get('isInstalled')) {
this.next();
} else if(Session.get('isInstalled') === false) {
console.log('go to install!');
this.render('install');
}
}
} else {
this.next();
}
});
And here is a more general pattern which allows you to set routes based on asynchronous conditions
Router.onBeforeAction(function (params) {
var self = this;
this.wait(function(){
Meteor.call('someMethod', function (err, result) {
Session.set('someMethodCalled', true);
// do whatever with result...
Session.set('someCondition', true);
});
return {
ready: function () {
return Session.get('someMethodCalled');
self.next();
}
}
});
if (this.ready()) {
if (Session.get('someCondition')) {
this.next();
} else if(Session.get('someCondition') === false) { // important to be explicit ===
this.render('someSpecificRoute');
}
}
});
来源:https://stackoverflow.com/questions/28305666/how-to-get-rid-of-meteor-template-flickers