Home forums Chart Support Context error on this.chart.render()

Tagged: 

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #32240

    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;
    #32250

    @jmings,

    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

Viewing 2 posts - 1 through 2 (of 2 total)

You must be logged in to reply to this topic.