2015-01-16 3 views
0

Я хочу создать диаграммы на основе данных из моей коллекции. Эти данные вызываются путем суммирования в моих настройках маршрутизатора и устанавливаются с помощью Session.data в функции template.rendered.IronRouter: шаблон визуализируется перед вызовом waitOn завершен

Meteor.call находится в функции waitOn. Если шаблон визуализирован, данных нет.

Я попытался onBeforeAction, действие, setTimeout ... но я не могу настроить функцию рендеринга до тех пор, пока не будут присутствовать данные вызова.

Я попытался установить вызовы в режимах onBeforeAction и onRun, в действии waitOn и данные функционируют как на моем RouteController, так и на Router.route.

Я завернул свой рендеринговый код с помощью setTimeout, но он не сработал.

Router.configure({ 
    layoutTemplate: 'global', 
    loadingTemplate: 'loading', 
    notFoundTemplate: 'notFound', 
}); 
Router.onBeforeAction("loading"); 

установлен в моих глобальных настройках маршрутизации.

Я уже пробовал следующие решения:
question 23575826
question 26198531
https://github.com/EventedMind/iron-router/issues/554#issuecomment-39002306
и больше в последние дни.

Есть ли какие-либо предложения по настройке моего маршрутизатора или другой способ решить эту проблему и получить данные, полученные вовремя? Я считаю, что выбрать npm-modules fiber/future, но я понятия не имею, как внедрять и использовать их.

Мои настройки: метеора v1.0.2.1

router.js с собственным контроллером

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 на:

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']); 
     }   
    }) 
    ]; 
}, 

и добавил test.coffee в/Lib:

_.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 

результат: мой цикл звонков.

Я проверил ответ от @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(); 
     };    
     }) 
     [...] 
    }) 
    ]; 
}, 

оба результата: мои звонки цикла.

+0

'waitOn' не будет работать с' Meteor.call' прямо из коробки, вам нужен еще более разработанный код, чтобы он работал; где вы видели этот пример? –

+0

Вы можете увидеть мою реализацию Meteor.callWithReady [здесь] (https://github.com/EventedMind/iron-router/issues/294). Он работает для нас в более ранних версиях IR, но я не тестировал его с 1.x. Вы можете попробовать заменить «Meteor.call» на «Meteor.callWithReady» и посмотреть, работает ли он. –

+0

@apendua это не из примера. я понял. Мне нужна сводная функция, чтобы суммировать некоторые данные коллекции, и я не знаю, как это будет работать с подписками, поэтому я выбрал вызовы ... – Skeltoras

ответ

0

Что вам не хватает здесь, так это то, что в вашем waitOn вам нужно вернуть список объектов, каждый из которых имеет метод ready, который действует как реактивный источник данных. К сожалению, Meteor.call не возвращает этот вид объекта, но, например, Meteor.subscribe делает.

Что вы можете сделать, это использовать следующую оболочку, но сначала убедитесь, что в ваш проект добавлен пакет reactive-var.

function waitUntilDone (action) { 
    var isReady = new ReactiveVar(false); 
    action(function() { 
    isReady.set(true); 
    }); 
    return { 
    ready: function() { 
     return isReady.get(); 
    } 
    }; 
} 

Теперь, вместо того, чтобы возвращать список результатов Meteor.call как этот

waitOn: function() { 
    return [ 
    Meteor.call(..., function() { ... }), 
    Meteor.call(..., function() { ... }), 
    // ... 
    ] 
} 

использовать вышеуказанную обертку следующим образом

waitOn: function() { 
    return [ 
    waitUntilDone(function(done) { 
     Meteor.call(..., function() { 
     // ... 
     done(); 
     }), 
    }), 
    // ... 
    ] 
} 
+0

Я протестировал его, но он начинает цитировать мои звонки. Может быть, он работает только с одним вызовом на каждую функцию? – Skeltoras

+0

Каждый «Meteor.call» должен быть обернут отдельно, если это то, о чем вы просите. Вы должны показать немного больше своего кода, если я хочу дать вам больше подсказок. –

+0

Вот что я сделал. Я также попытался поместить все в одну функцию waitUntilDone. – Skeltoras

0

Update: После нескольких дней тестирования я изменил функции на Meteor.publish вместо Meteor.method, так что функция waitOn теперь работает. Я не понимал, что это также работает с публикацией. Примеры для совокупных db-вызовов - все с 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, но данные не отображаются в моей диаграмме без обновления вручную моего шаблона.

Смежные вопросы