IronRouter:在waitOn中的调用完成之前呈现模板 [英] IronRouter: template is rendered before call in waitOn is finished
问题描述
我想基于我的收藏中的数据创建图表. 这些数据由我的路由器设置中的汇总提取调用,并由template.rendered函数中的Session.data设置.
I want to create charts based on data from my collection. This data is called by an aggregate pull in my router-settings and set by Session.data in the template.rendered function.
Meteor.call放置在waitOn函数中. 如果呈现了模板,则数据不存在.
The Meteor.call is placed in the waitOn-function. If the template is rendered, the data is not present.
我尝试了onBeforeAction,action,setTimeout ...,但是我无法将渲染功能设置为等到调用数据出现后再使用.
I tried onBeforeAction, action, setTimeout... but i can't set the render-function to wait until the call-data is present.
我试图在onBeforeAction和onRun挂钩中设置调用,在动作中,在RouteController和Router.route上都设置了waitOn和data函数.
I tried to set the calls in the onBeforeAction and onRun hooks, in the action, waitOn and data functions both on my RouteController and Router.route.
我用setTimeout包装了呈现的代码,但是没有用.
I wrapped my rendered-code with setTimeout, but it didn't work.
Router.configure({
layoutTemplate: 'global',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
});
Router.onBeforeAction("loading");
是在我的全局路由设置中设置的.
is set in my global routing settings.
我已经尝试了以下解决方案:
问题23575826
问题26198531
https://github.com/EventedMind/iron-router/issues/554 #issuecomment-39002306
在过去的日子里还有更多.
I've already tried following solutions:
question 23575826
question 26198531
https://github.com/EventedMind/iron-router/issues/554#issuecomment-39002306
and more in the last days.
是否对我的路由器设置有任何建议,或者是否有其他方法可以解决此问题并及时呈现数据? 我考虑选择npm-modules光纤/期货,但我不知道如何嵌入和使用它们.
Is there any suggestion for my router settings or another way to solve this problem and get the data rendered in time? I consider to pick the npm-modules fiber/future, but i've no idea how to embed and use them.
我的设置: 流星是v1.0.2.1
My settings: Meteor is v1.0.2.1
router.js (带有自己的控制器)
router.js with own controller
StatsController = RouteController.extend({
template: 'statsShow',
waitOn: function () {
return [
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'SellerOne', 2014, function(error, result){
if(!error)
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
}),
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'SellerTwo', 2014, function(error, result){
if(!error)
Session.set('info3Units', result['units']);
Session.set('info3Volumes', result['volumes']);
}),
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'SellerThree', 2014, function(error, result){
if(!error)
Session.set('avaUnits', result['units']);
Session.set('avaVolumes', result['volumes']);
})
];
},
data: function () {
return Books.findOne({_id: this.params._id});
},
action: function () {
if (!this.ready()) {
this.render('Loading');
} else {
this.render();
}
}
});
Router.route('stats/show/', {
name: 'stats.show',
controller: 'TestController'
});
methods.js
Meteor.methods({
saleGetDataPerYear: function(bookId, seller, year) {
var sellerUnits = [];
var sellerVolumes = [];
var resultData = {};
var pipeline = [
{
$match : { bookId: bookId, salesSeller: seller, salesYear: year }
},
{
$group : {
_id : {
sale: { "salesMonth": "$salesMonth" }
},
units: { $sum: "$salesUnits" },
volumes: { $sum: "$salesVolumes" },
month: { $first: "$salesMonth" },
year: { $first: "$salesYear" },
seller: { $first: "$salesSeller" }
}
},
{
$sort : {
month: 1
}
}
];
result = Sales.aggregate(pipeline);
if(result){
sellerUnits.push(seller);
sellerVolumes.push(seller);
result.forEach(function(data){
sellerUnits.push(data.units);
sellerVolumes.push(data.volumes);
});
resultData['units'] = sellerUnits;
resultData['volumes'] = sellerVolumes;
}
if(resultData){
return resultData;
} else {
throw new Meteor.Error("no-data", "No Data collected");
}
}
模板
//-- template rendered functions
Template.statsShow.rendered = function(){
var chartUnitsBrockhaus = Session.get('brockhausUnits');
var chartUnitsInfo3 = Session.get('info3Units');
var chartUnitsAva = Session.get('avaUnits');
var chartUnitsSumme = Session.get('sumUnits');
console.log(chartUnitsBrockhaus);
var chartUnits = c3.generate({
bindto: this.find('.chartUnits'),
data: {
columns: [
chartUnitsBrockhaus,
chartUnitsInfo3,
chartUnitsAva,
chartUnitsSumme
],
type: 'bar',
types: {
Summe: 'spline',
},
},
axis: {
x: {
type: 'category',
categories: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
}
},
bar: {
width: {
ratio: 0.5
}
}
});
};
包装
accounts-password 1.0.5
accounts-ui 1.1.4
alanning:roles 1.2.13
aldeed:autoform 4.2.2
aldeed:autoform-select2 1.0.3
aldeed:collection2 2.3.1
aldeed:simple-schema 1.3.0
anti:fake 0.4.1
chrismbeckett:fontawesome4 4.2.2
coffeescript 1.0.5
ctjp:meteor-bootstrap-switch 3.3.1_1
dburles:collection-helpers 1.0.2
francocatena:status 1.0.3
iron:router 1.0.7
lepozepo:accounting 1.0.0
less 1.0.12
matteodem:easy-search 1.4.6
meteor-platform 1.2.1
meteorhacks:aggregate 1.1.0
mrt:jquery-csv 0.7.1
natestrauser:select2 3.5.1
nemo64:bootstrap 3.3.1_1
ongoworks:security 1.0.1
peerlibrary:xml2js 0.4.4_3
peernohell:c3 1.1.2
sacha:spin 2.0.4
service-configuration 1.0.3
underscore 1.0.2
zimme:select2-bootstrap3-css 1.4.1
修改
正如@DavidWeldon提到的,我将我的waitOn函数更改为:
Edit
as @DavidWeldon mentioned i changed my waitOn function to:
waitOn: function () {
return [
// first call
Meteor.callWithReady('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Brockhaus', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
};
}),
// second call
Meteor.callWithReady('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Info3', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
};
}),
// third call
Meteor.callWithReady('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'AVA', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
};
}),
// fourth call
Meteor.callWithReady('saleGetSumDataPerYear', 'nYWpgxR3kEY8kwBkA', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('sumUnits', result['units']);
Session.set('sumVolumes', result['volumes']);
}
})
];
},
并在/lib下添加 test.coffee :
_.defaults Meteor,
callWithReady: (method, options...) ->
dep = new Deps.Dependency
ready = false
lastOption = _.last options
if _.isFunction lastOption
Meteor.apply method, _.initial(options), (err, result) ->
lastOption err, result
ready = true
dep.changed()
else
Meteor.apply method, options, (err, result) ->
ready = true
dep.changed()
ready: ->
dep.depend()
ready
结果是:我的电话循环.
result is: my calls loop.
我测试了@apendua的答案.
I tested the answer from @apendua.
function waitUntilDone (action) {
var isReady = new ReactiveVar(false);
action(function () {
isReady.set(true);
});
return {
ready: function () {
return isReady.get();
}
};
}
waitOn: function () {
return [
// first call
waitUntilDone(function(done) {
Meteor.callWithReady('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Brockhaus', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
};
done();
})
}),
// second call
waitUntilDone(function(done) {
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Info3', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
done();
};
})
}),
// third call
waitUntilDone(function(done) {
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'AVA', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
done();
};
})
}),
// fourth call
waitUntilDone(function(done) {
Meteor.call('saleGetSumDataPerYear', 'nYWpgxR3kEY8kwBkA', 2014, function(error, result){
if(!error) {
console.log(result);
Session.set('sumUnits', result['units']);
Session.set('sumVolumes', result['volumes']);
done();
}
})
})
];
},
或
waitOn: function () {
return [
// first call
waitUntilDone(function(done) {
Meteor.callWithReady('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Brockhaus', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
};
done();
}),
Meteor.call('saleGetDataPerYear', 'nYWpgxR3kEY8kwBkA', 'Info3', 2014, function(error, result){
if(!error) {
console.log(result); //debug
Session.set('brockhausUnits', result['units']);
Session.set('brockhausVolumes', result['volumes']);
done();
};
})
[...]
})
];
},
两个结果都是:我的通话循环.
both results are: my calls loop.
推荐答案
更新:经过几天的测试,我将功能更改为Meteor.publish
而不是Meteor.method
,因此waitOn
功能现在可以使用了.
我没有意识到这也适用于发布.汇总数据库调用的示例全都用Meteor.method
.
Update: After some days of testing i changed the functions to Meteor.publish
instead of Meteor.method
so the waitOn
function is now working.
i didn't realise that this also work with publish. The examples for aggregate db-calls are all with Meteor.method
.
publications.js
Meteor.publish('saleGetAllDataPerYear', function(bookId, year) {
self = this;
var pipeBH = [];
var resultBH = '';
var unitsBH = [];
var volumesBH = [];
var monthBH = [];
var pipeI3 = [];
var resultI3 = '';
var unitsI3 = [];
var volumesI3 = [];
var monthI3 = [];
var pipeAVA = [];
var resultAVA = '';
var unitsAVA = [];
var volumesAVA = [];
var monthAVA = [];
var pipeSum = [];
var resultSum = '';
var unitsSum = [];
var volumesSum = [];
var monthSum = [];
// Set Brockhaus data
pipeBH = [
{ $match : { bookId: bookId, salesSeller: 'Brockhaus', salesYear: year } },
{ $group : { _id : { sale: { "salesMonth": "$salesMonth" } },
units: { $sum: "$salesUnits" }, volumes: { $sum: "$salesVolumes" }, month: { $first: "$salesMonth" }, year: { $first: "$salesYear" }, seller: { $first: "$salesSeller" }
}
},
{ $sort : { month: 1 } }
];
resultBH = Sales.aggregate(pipeBH);
if(resultBH != ''){
unitsBH.push('Brockhaus');
volumesBH.push('Brockhaus');
resultBH.forEach(function(data){
unitsBH.push(data.units);
volumesBH.push(data.volumes);
monthBH.push(data.month);
});
self.added('stats', Random.id(), {seller: 'Brockhaus', units: unitsBH, volumes: volumesBH, month: monthBH, year: year});
self.ready();
} else {
self.ready();
}
// Set Info3 data
pipeI3 = [
{ $match : { bookId: bookId, salesSeller: 'Info3', salesYear: year } },
{ $group : { _id : { sale: { "salesMonth": "$salesMonth" } },
units: { $sum: "$salesUnits" }, volumes: { $sum: "$salesVolumes" }, month: { $first: "$salesMonth" }, year: { $first: "$salesYear" }, seller: { $first: "$salesSeller" }
}
},
{ $sort : { month: 1 } }
];
resultI3 = Sales.aggregate(pipeI3);
if(resultI3 != ''){
unitsI3.push('Info3');
volumesI3.push('Info3');
resultI3.forEach(function(data){
unitsI3.push(data.units);
volumesI3.push(data.volumes);
monthI3.push(data.month);
});
self.added('stats', Random.id(), {seller: 'Info3', units: unitsI3, volumes: volumesI3, month: monthI3, year: year});
self.ready();
} else {
self.ready();
}
// Set AVA data
pipeAVA = [
{ $match : { bookId: bookId, salesSeller: 'AVA', salesYear: year } },
{ $group : { _id : { sale: { "salesMonth": "$salesMonth" } },
units: { $sum: "$salesUnits" }, volumes: { $sum: "$salesVolumes" }, month: { $first: "$salesMonth" }, year: { $first: "$salesYear" }, seller: { $first: "$salesSeller" }
}
},
{ $sort : { month: 1 } }
];
resultAVA = Sales.aggregate(pipeAVA);
if(resultAVA != ''){
unitsAVA.push('AVA');
volumesAVA.push('AVA');
resultAVA.forEach(function(data){
unitsAVA.push(data.units);
volumesAVA.push(data.volumes);
monthAVA.push(data.month);
});
self.added('stats', Random.id(), {seller: 'AVA', units: unitsAVA, volumes: volumesAVA, month: monthAVA, year: year});
self.ready();
} else {
self.ready();
}
// Set Sum data
pipeSum = [
{ $match : { bookId: bookId, salesYear: year } },
{ $group : { _id : { sale: { "salesMonth": "$salesMonth" } },
units: { $sum: "$salesUnits" }, volumes: { $sum: "$salesVolumes" }, month: { $first: "$salesMonth" }, year: { $first: "$salesYear" }, seller: { $first: "$salesSeller" }
}
},
{ $sort : { month: 1 } }
];
resultSum = Sales.aggregate(pipeSum);
if(resultSum != ''){
unitsSum.push('Summe');
volumesSum.push('Summe');
resultSum.forEach(function(data){
unitsSum.push(data.units);
volumesSum.push(data.volumes);
monthSum.push(data.month);
});
self.added('stats', Random.id(), {seller: 'Summe', units: unitsSum, volumes: volumesSum, month: monthSum, year: year});
self.ready();
} else {
self.ready();
}
});
router.js
waitOn: function () {
year = Number(Session.get('year'));
return [
Meteor.subscribe('saleGetAllDataPerYear', this.params._id, year),
Meteor.subscribe('getStats')
];
},
感谢@JeremyS的另一种启发.听起来这是更好的解决方案,因为现在waitOn
函数可以工作了,但是如果没有手动刷新模板,数据就不会在我的图表中呈现.
Thanks to @JeremyS for the inspiration on another way. That sounds like the better solution because now the waitOn
function works but the data is not rendered in my chart without manual refresh of my template.
这篇关于IronRouter:在waitOn中的调用完成之前呈现模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!