铁路由器:模板在waltOn调用完成之前呈现

时间:2015-01-16 18:22:24

标签: meteor iron-router

我想根据我的收藏品中的数据创建图表。 这个数据由我的路由器设置中的聚合拉取调用,并由template.rendered函数中的Session.data设置。

Meteor.call放在waitOn函数中。 如果渲染模板,则不存在数据。

我尝试了onBeforeAction,action,setTimeout ......但我不能设置渲染函数等到调用数据出现。

我尝试在我的RouteController和Router.route上的action,waitOn和data函数中设置onBeforeAction和onRun挂钩中的调用。

我用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光纤/未来,但我不知道如何嵌入和使用它们。

我的设置: 流星是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']); 
      }           
    })   
  ];
},

并在/ 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

结果是:我的调用循环。

我测试了@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();
        };            
      })
      [...]
    })   
  ];
},

两个结果都是:我的呼叫循环。

2 个答案:

答案 0 :(得分: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();
      }),
    }),
    // ...
  ]
}

答案 1 :(得分:0)

更新:经过几天的测试后,我将功能更改为Meteor.publish而不是Meteor.method,因此waitOn功能正在运行。 我没有意识到这也适用于发布。聚合db-calls的示例都是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函数可以正常工作,但如果没有手动刷新模板,数据就不会在我的图表中呈现。