Chart js cannot read property 'getContext' of null only AFTER new document in collection?


#1

I have two selects that set session vars and after the 2nd is selected, a chart is loaded. This works just fine until I add a new document to the collection that serves as a key “index” of sorts in the compiling of the dataset. This new document has one common field with the document that generates the dataset that won’t render – that field is “season”, which is the 1st of those 2 selects.

The charts do not display the collection directly, as you will see there is quite a bit of data massaging going on (probably could withstand some improvements, but that’s not my issue).

My issue is that after inserting a new document with a common “season” field, any other docs used in the dataset with that same “season” field throw the getContext is null error. Other charts with different “season” fields display just fine… until I insert a document with that “season” field. If I remove that newly/recently inserted document, the chart renders again just fine.

Apologies for the data overload included below - I am dumbfounded here.

fyi, thisWeek.js:72 is from the “redrawChart” function below:

var ctx  = document.getElementById("twChart").getContext("2d");

Error:

thisWeek.js:72 Uncaught TypeError: Cannot read property 'getContext' of null
    at redrawChart (thisWeek.js:72)
    at LocalCollection.Cursor.change #slateSelect (thisWeek.js:213)
    at blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:3775
    at Function.Template._withTemplateInstanceFunc (blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:3744)
    at Blaze.View.<anonymous> (blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:3774)
    at blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:2617
    at Object.Blaze._withCurrentView (blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:2271)
    at Blaze._DOMRange.<anonymous> (blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:2616)
    at HTMLSelectElement.<anonymous> (blaze.js?hash=f33d3dfed63a491d24e3aa07ad66c24b5fe8c761:863)
    at HTMLDivElement.dispatch (jquery.js?hash=0c5fac3e4b18ec685e561deac3634fb49bc807e5:4722)

html:

<form class="form-inline">
			<div class="form-group">
				<label for="slateSsnSelect">Season/Tournament</label>
				<select name="sltSsn" id="slateSsnSelect" class="form-control">
					{{#each slateseason in slateseasons}}
						<option value="{{slateseason.season}}">{{slateseason.season}}</option> 
					{{/each}}
				</select>
			</div>
		
			<div class="form-group">
				<label for="slateSelect">Slate</label>
				<select name="sltChrtSlct" id="slateSelect" class="form-control">
					<option>Select a Slate...</option>
					{{#each slate in slates}}
						<option value="{{slate.slatename}}">{{slate.slatename}}</option> 
					{{/each}}
				</select>
			</div>
		</form>

Template Events:

'change #slateSsnSelect': function(){
        Session.set('slateSeason', $('#slateSsnSelect').val() );
    },

    'change #slateSelect': function(){
    	$('#twChart').remove();
    	$('.chrtDiv').append('<canvas id="twChart" class="img-responsive"></canvas>');
        
        Session.set('selectedSlate', $('#slateSelect').val() );
        
        var lg = Meteor.user().profile.lgName
        var ssn = Session.get('slateSeason');
    	var slt = Session.get('selectedSlate');

        redrawChart();
    }
});

Template helpers:

 slateseasons: function(){
        var ssnsQry = Seasons.find({},{sort: {createdAt:-1} }).fetch();
        if(ssnsQry.length > 0){
            Session.set('slateSeason', ssnsQry[0].season);
            return ssnsQry;
        } 
    },

    slates: function(){
        var sltSsn = Session.get('slateSeason');
        var sltsQry = Slates.find({season: sltSsn},{sort: {createdAt:-1} }).fetch();
        if(sltsQry.length > 0){
            Session.set('selectedSlate', sltsQry[0].slatename);
            return sltsQry;
        }
    }

Chart function:

function redrawChart(){
	$('#twChart').remove();
    $('.chrtDiv').append('<canvas id="twChart" class="img-responsive"></canvas>');
    
    var lg = Meteor.user().profile.lgName;
    var lgType = Leagues.find({lgname: lg},{fields: {scoreType:1} }).fetch();
    var players = _.uniq(Results.find({"league": lg}, 
                                    {sort: {"user":1}}, 
                                    {fields: {"user":1, _id:0}}).fetch().map(function(x) { return x.user;}), true );


  var ssn = Session.get('slateSeason');
  var slt = Session.get('selectedSlate');

  var dataset = Results.find({"season":ssn, "slate":slt, "league": lg}, {fields: {"user":1, "pointsWon":1 }}, {sort:{"user":1}}).fetch();
   
   
    var plyrsArr = _(dataset).groupBy('user');

   var ptsArr = _(plyrsArr).map(function(g, key){
                        return { user: key,
                         pointsWon: _(g).reduce(function(m,x) { return m + x.pointsWon;}, 0) };
                        });
 
    var labels = [], data=[];
      
        ptsArr.forEach(function(item) {
            labels.push(item.user);
            data.push(parseFloat(item.pointsWon));
        });
    

    var totdata = {
        labels: labels,
        datasets: [{
            fillColor: "#E16B6B",                
            data: data
        }]
    };

    var options = {
        responsive: true,
        scaleBeginAtZero:true,
        maintainAspectRatio: false,
        barBeginAtOrigin:true
    };

    var ctx  = document.getElementById("twChart").getContext("2d");
	    ctx.canvas.width = 300;
	    ctx.canvas.height = 400;

    new Chart(ctx).Bar(totdata, options);
}

#2

After many hours of banging my head against a brick wall, I finally realized that the helper function in the html creating the chart div was the problem.

Right below the html shown above I had:

{{#if chartExists}}
		<div class="chrtDiv">
			<canvas id="twChart" class="img-responsive"></canvas>
		</div>
		{{else}}
			<div>
				<h2> <img src="dunno.png" class="img-responsive" alt=""> No data...</h2>
			</div>
		{{/if}}

The “chrtExists” helper was just checking to see if there was any Results documents available via the find() filters “season” and “slate”. I tried to be cute there by showing a gif in the event there was no data for the chart. not sure why exactly… I tried setting a session var with the resulting dataset used to populate the chart and have the helper check for that, but that didn’t work either.

I also put the canvas in the “else” section of the html but that also failed. Somehow that helper won’t let that canvas render…

anyway, i get to move on to the next thing now :sweat_smile: