You must be logged in to post your query.
Home › Forums › Chart Support › Context error on this.chart.render()
Tagged: Context error
I’m getting an “Uncaught TypeError: Cannot read property ‘render’ of undefined” in my toggle data series function on line “this.chart.render();”. I think this is an error with my this context/binding/etc. Any help?
import React, { Component } from 'react';
import PageNumber from './common/pageNumber';
import { paginate } from '../utils/paginate';
import Filter from "./common/filter";
//import trump from '../images/trump.jpeg';/
import trump from "../images/48397172_587551211695038_9179185258694705152_n.png"
import '../style/graphPage.css';
import CanvasJSReact from '../utils/canvasjs.react';
import Calendar from "react-range-calendar";
import TweetRow from './tweetRow';
import AVLTree from 'avl';
import { LoadingButton } from './common/loadingButton';
import ToggleFilter from './common/toggleFilter';
import NavBar from "./common/navBar";
import TweetFilters from './common/tweetFilters';
// Create chart object
let CanvasJSChart = CanvasJSReact.CanvasJSChart;
// Establish our backend base URL
const baseURL = "http://localhost:8081";
class DataAnalyticsPage extends Component {
  constructor(props) {
		super(props);
		this.state = { 
      months: [], // Possible months  
      selectedMonth: " -- select a month -- ", // Current selected month
      options: {
        theme: "light2",
        animationEnabled: true,
        zoomEnabled: true,
        title:{
          text: "Units Sold VS Profit"
        },
        subtitles: [{
          text: "Click Legend to Hide or Unhide Data Series"
        }],
        axisX: {
          title: "States"
        },
        axisY: {
          title: "Units Sold",
          titleFontColor: "#6D78AD",
          lineColor: "#6D78AD",
          labelFontColor: "#6D78AD",
          tickColor: "#6D78AD"
        },
        axisY2: {
          title: "Profit in USD",
          titleFontColor: "#51CDA0",
          lineColor: "#51CDA0",
          labelFontColor: "#51CDA0",
          tickColor: "#51CDA0"
        },
        toolTip: {
          shared: true
        },
        legend: {
          cursor: "pointer",
          itemclick: this.toggleDataSeries
        },
        data: [{
          type: "spline",
          name: "US CPI",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "France CPI",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "Canada CPI",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "Germany CPI",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "UK CPI",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "US Unemployment",
          axisYType: "secondary",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "France Unemployment",
          axisYType: "secondary",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "Canada Unemployment",
          axisYType: "secondary",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "Germany Unemployment",
          axisYType: "secondary",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        },
        {
          type: "spline",
          name: "UK Unemployment",
          axisYType: "secondary",
          showInLegend: true,
          xValueFormatString: "MMM YYYY",
          yValueFormatString: "#,##0 Units",
          dataPoints: []
        }
        ]}, // Graph options for CanvasJSReact graph
      
      // Misc
      loading: false, // Is the page currently loading
     };
		this.toggleDataSeries = this.toggleDataSeries.bind(this);
	}
  
  toggleDataSeries(e){
		if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
			e.dataSeries.visible = false;
		}
		else{
			e.dataSeries.visible = true;
		}
		this.chart.render();
	}
  componentDidMount() {
    this.getCPI();
    this.getUnemployment();
    // this.getApprovals();
  }
  getCPI() {
    // Establish URl to backend
    let dataURL = baseURL + "/CPI";
    // Make backend calls
    fetch(dataURL, {
      method: 'GET' // The type of HTTP request.
    })
      .then(this.checkStatus)
      .then(res => res.json()) // Convert the response data to a JSON.
      .then(data => 
        {
          // Get current options and chart
          let opts = this.state.options;
          let chart = this.chart;
          // Update data points
          let USData = [];
          let FranceData = [];
          let GermanyData = [];
          let UKData = [];
          let CanadaData = [];
          let months = [];
          for (var i = 0; i < data.length; i++) {
            months.push(<option key={i} value={data[i].date}>{data[i].date}</option>)
            if (data[i].country.localeCompare("US") === 0) {
              USData.push({
                x: new Date(data[i].date),
                y: data[i].CPI
              });
            } else if (data[i].country.localeCompare("France") === 0) {
              FranceData.push({
                x: new Date(data[i].date),
                y: data[i].CPI
              });
            } else if (data[i].country.localeCompare("Germany") === 0) {
              GermanyData.push({
                x: new Date(data[i].date),
                y: data[i].CPI
              });
            } else if (data[i].country.localeCompare("UK") === 0) {
              UKData.push({
                x: new Date(data[i].date),
                y: data[i].CPI
              });
            } else if (data[i].country.localeCompare("Canada") === 0) {
              CanadaData.push({
                x: new Date(data[i].date),
                y: data[i].CPI
              });
            };
          }
          
          // Update the current graph options
          opts.data[0].dataPoints = USData;
          opts.data[1].dataPoints = FranceData;
          opts.data[2].dataPoints = CanadaData;
          opts.data[3].dataPoints = GermanyData;
          opts.data[4].dataPoints = UKData;
          // Set state and rerender the graph
          this.setState({
            options: opts,
            months: months
          }, () => {
            chart.render();
          });
        })
    .then()
    .catch(err => console.log(err))	// Print the error if there is one.
  }
  getUnemployment() {
    // Establish URl to backend
    let dataURL = baseURL + "/Unemployment";
    // Make backend calls
    fetch(dataURL, {
      method: 'GET' // The type of HTTP request.
    })
      .then(this.checkStatus)
      .then(res => res.json()) // Convert the response data to a JSON.
      .then(data => 
        {
          // Get current options and chart
          let opts = this.state.options;
          let chart = this.chart;
          // Update data points
          let USData = [];
          let FranceData = [];
          let GermanyData = [];
          let UKData = [];
          let CanadaData = [];
          for (var i = 0; i < data.length; i++) {
            if (data[i].country.localeCompare("US") === 0) {
              USData.push({
                x: new Date(data[i].date),
                y: data[i].rate
              });
            } else if (data[i].country.localeCompare("France") === 0) {
              FranceData.push({
                x: new Date(data[i].date),
                y: data[i].rate
              });
            } else if (data[i].country.localeCompare("Germany") === 0) {
              GermanyData.push({
                x: new Date(data[i].date),
                y: data[i].rate
              });
            } else if (data[i].country.localeCompare("UK") === 0) {
              UKData.push({
                x: new Date(data[i].date),
                y: data[i].rate
              });
            } else if (data[i].country.localeCompare("Canada") === 0) {
              CanadaData.push({
                x: new Date(data[i].date),
                y: data[i].rate
              });
            };
          }
          
          // Update the current graph options
          opts.data[5].dataPoints = USData;
          opts.data[6].dataPoints = FranceData;
          opts.data[7].dataPoints = CanadaData;
          opts.data[8].dataPoints = GermanyData;
          opts.data[9].dataPoints = UKData;
          // Set state and rerender the graph
          this.setState({
            options: opts
          }, () => {
            chart.render();
          });
        })
    .then()
    .catch(err => console.log(err))	// Print the error if there is one.
  }
  // ---------------------------------------- EVENT HANDLERS ---------------------------------------------- //
  /**
   * This function handles the event raised by PageNumber onPageChange
   * @param {int} page - the page number being changed to
   */
  // Handle the event raised by PageNumber onPageChange
  handlePageChange = (page) => {
    console.log('handling page = ' + page);
    const curPage = this.state.currentPage;
    const pageSize = this.state.pageSize;
    // Store the current TweetRow items
    let currentTweets = this.state.currentTweets;
    const displayedTweets = paginate(currentTweets, curPage, pageSize);
    let startIndex = (curPage - 1) * pageSize;
    for (var i = 0; i < this.state.pageSize; i++) {
      currentTweets[startIndex + i] = displayedTweets[i];
    }
    console.log(displayedTweets);
    // Set state's active page and current TweetRow items
    this.setState({ currentPage: page, currentTweets: currentTweets });
  }
  
  /**
   * Called when a dataset is selected from the dropdown
   * @param {event} e - Event that triggered this handler to be called. The data name is available
   * at e.target.value
   */
  handleSelectMonth = (e) => {
    this.setState({ selectedMonth: e.target.value });
  }
  /**
   * 
   * @param {*} tweet 
   * @param {*} added 
   * @param {*} id 
   */
  handleSearch = (e) => {
  }
  // ---------------------------------------- HELPER FUNCTIONS ---------------------------------------------- //
  /**
   * This function updates the tweets stored in this.state.currentTweets in order to cause the page to re-render
   * Currently, I am creating a new TweetRow object to replace the existing one, but I don't know if this is correct
   * And I'm obviously not getting the tweets to reload on pagechange
   * @param {int} tweet - the embedded tweet's official Twitter id
   * @param {boolean} added - has the tweet been added by the current user
   * @param {int} id - the local id of the TweetRow object; ordered by however database returns values
   */
  updateCurrentTweets(tweet, added, id) {
    const curPage = this.state.currentPage;
    const pageSize = this.state.pageSize;
    // Store the current TweetRow items
    let currentTweets = this.state.currentTweets;
    let startIndex = (curPage - 1) * pageSize;
    let insert = <TweetRow id={id} tweetId={tweet} added={added} onAdd={this.handleAdd}/>;
    currentTweets[startIndex + id] = insert;
    console.log('added is ' + added + '; id is ' + id);
    this.setState( { currentTweets: currentTweets });
  }
  
  /**
   * CheckStatus function ensures we get an okay response from the server
   * @param {response} response - response from fetch
   * @return {response} either returns the same input or throws an error
   */
  checkStatus(response) {
    if (response.ok) {
      return response;
    } else {
      throw Error("Error in request: " + response.statusText);
    }
  }
  render() {
    const { selectedMonth, months, loading, options } = this.state;
    console.log(months);
    return (
      <main className="main">
        <NavBar/>
        <section className="header">
          <h1>Data Analytics Page</h1>
          <p>Description, Description, Description, Description, Description, Description, Description...</p>
        </section>
        <CanvasJSChart 
          options={options}
          onRef={ref => this.chart = ref}
        />
        <section id="tweetSearch">
          <select value={ selectedMonth } onChange={this.handleSelectMonth} className="dropdown" id="monthDropdown">
            <option select key={-1} value={selectedMonth}> -- select a month -- </option>
            { months }
          </select>
          <section id="tweetFilters">
            <TweetFilters/>
            <LoadingButton 
              isLoading={loading} 
              search={this.handleSearch}
            />
          </section>
        </section>
      </main>
    );
  }
}
 
export default DataAnalyticsPage;In the code sample that you have shared, replacing this.chart.render() with e.chart.render() should work fine. Please take a look at this documentation page for more information to Hide Unhide Data Series on Legend Click.
If you are still facing any issue, kindly create a sample project reproducing the issue and share it with us over Google-Drive or Onedrive so that we can run the code locally, understand the scenario better and help you out.
___________
Indranil Deo
Team CanvasJS
Tagged: Context error
You must be logged in to reply to this topic.