2
votes

I have multiple charts on a dashboard that shows counts, group bys etc. Backend data has over million rows. I have decided not to use subscriptions. I don't need reactive updates to the charts.

My Server methods are using rawCollection, running aggregations to get back results and I am assigning data to my chart objects via session variables that I am setting in my client callbacks.

Server method:

function purchasedItemDollarsByCategory () {
    Future = Npm.require('fibers/future');
    var iCat = new Future();
    Purchasing.rawCollection().aggregate([
            {
                $project: {
                    "GLCodeName": 1,
                    "Amount" : 1
                }
            },
            {
                $group : {
                    _id: "$GLCodeName",
                    amount: { $sum : "$Amount" }
                }
            },
            {
                $sort :
                    {_id : 1}
            }
        ],
        function(err,docs) {
            if (err) {
                iCat.throw(err);
            } else {
                iCat.return(docs);
            }
        }
    );
    return iCat.wait();
}

In the template, I am calling

function getPurchasedItemDollarsByCategory () {
    Meteor.call('purchasedItemDollarsByCategory', function (err, results) {
        if (err) {
            toastr.error('Something went wrong. Could not retrieve purchased Item  count');
            return false;
        } else {
            Session.set( 'purchasedItemDollarsByCategory', results);
        }
    })
}

Now, I am using another function to shape the data for a chart:

function getPurchasedItemCountByCategoryChartData () {
    var allItemsPurchasedByCategory = Session.get('purchasedItemCountByCategory');
    var allGlCodes = [];
    var allItemPurchasedCountDataPoints = [];
    var contractedPurchasedCountDataPoints = [];
    _.forEach(allItemsPurchasedByCategory, function(d) {
        allGlCodes.push(d._id);
        allItemPurchasedCountDataPoints.push(d.items);
    });
    Session.set('allGlCodes', allGlCodes);
    Session.set('allItemPurchasedCountDataPoints', allItemPurchasedCountDataPoints);
}

Now I am assigning 'allGlCodes' and 'allItemPurchasedCountDataPoints' to highcharts config object in Template onRendered event.

Server method is working fine. Client is getting the data as well. But rendering is happening before the data is coming back. So the chart renders empty. But if I click around the app and come back to this page, I see the data. I am not sure if I understand exactly what is happening but I am guessing that the data is eventually coming back and populating the session variable and since the session is sticky, I see the data after a delay.

I would like not to render till the data comes back. So I have created a ReactiveVar in Template onCreated.

this.isLoadingA = new ReactiveVar( false );
this.isLoadingB = new ReactiveVar( false );
this.isLoading = new ReactiveVar ( this.isLoadingA && this.isLoadingB );

Now the question is where should I set these to false. I have multiple server calls going on. I could have a isLoading for each call and create a allDataReady variable. But if I try to set in my success callback to the server method:

Template.instance().isLoadingA.set( true );

I get the following error:

TypeError: Cannot read property 'isLoadingA' of null

I hope I am explaining the problem and my attempts clearly. Any thoughts?

1
I know this was a long time ago, but you never added an answer. Did you solve this? - Cos

1 Answers

0
votes

I believe that Template.instance() is unavailable in callbacks from Meteor methods on its own. You could instead do:

exampleHelper() {
    var template = Template.instance();
    Meteor.call( 'example', function(error, results) {
        console.log(Template.instance()); // Undefined
        console.log(template);  // What you want in order to set your reactive variables.
    });
}

That would allow you to use reactive vars and setting the state appropriately in callbacks.