I have the following function which constructs one or more y-axes for a Highcharts chart, though my problem has little or nothing to do with the Highcharts API.
_constructYAxes: function(yAxes) {
if (yAxes) {
var highChartYAxes = [];
for (var i = 0; i < yAxes.length; i++) {
var kpiUnits = yAxes[i].units;
var axisUnits = 'units ' + i;
var axisLabel = 'label ' + i;
// construct an Highcharts y-axis object
var yAxis = {
labels: {
formatter: function() {
return this.value + ' ' + axisUnits;
}
},
title: {
text: axisLabel
},
};
highChartYAxes.push(yAxis);
}
// pass all the y-axes to the chart
this.chartOpts.yAxis = highChartYAxes;
}
}
The problem is that the same label is used for each y-axis, even though the title is displayed correctly. The difference betweent hese two is that the former is calculated by invoking a function
labels: {
formatter: function() {
return this.value + ' ' + axisUnits;
}
},
So if I have a chart with 3 y-axes, the label “units 2” appears on all of them.
I think the problem is that the formatter function closes over the value of axisUnits in the last iteration of the loop, such that when the function is invoked (by Highcharts), it uses the same value of axisUnits each time.
What can I do to force the function to use the i-th value of axisUnits each time it is invoked instead?
Clearly my understanding of JavaScript scoping is somewhat lacking (I am frequently surprised by what this evaluates to in different contexts). If anyone knows of some good online resources that might help me to get this straight, please send them my way.
axisLabelis passed as a string directly and does not change.However,
axisUnitsis not directly passed. It’s only fetched when the function is called. The problem is that aforloop does not create a new scope, so for all iterations there is only oneaxisUnits, which causes all labels to have an equal text.You can solve this by creating a closure. This way, the string is directly passed and “freezed”: