Italo Borges
Italo Borges

Reputation: 2554

React Chart.js onClick for custom legends

I'm using react-chartjs-2 to create a Line chart for my application.

For this app, I did a legend customisation and I could generate them using this:

// Chart component
<Line ref={ (chart) => chart ? this.insertLegends(chart) : null }
      data={this.state.chart} 
      options={this.state.options}  
/>

// Method which insert the html content
insertLegends(chart) {
   this.refs.chartLegendContainerGlobal.innerHTML = chart.chart_instance.generateLegend();
}

First, is this a right approach? I had to create an inline condition inside the component to prevent chart to be null.

Second, how and where can I put an onClick event for each legend?

I'm very lost on this, is there a better way to do this legend customisation??

Upvotes: 0

Views: 6334

Answers (2)

Italo Borges
Italo Borges

Reputation: 2554

After some trouble and research, I figure out how to add the legend and control the click inside of it.

// Inside my render method I added a simple ref to my component
<Line ref='chart' data={this.convertData(this.props.data)}  options={this.state.options} />

// Inside this method I'm able to get all the references that 
// I need to inject the html inside a container for the legends and 
// also to assign a click for each legend label
componentDidMount() {
   let legends = this.refs.chart.chart_instance.generateLegend();
   this.refs.chartLegendContainer.innerHTML = legends;

   $(this.refs.chartLegendContainer).find('.legend-item').on('click', (e) => {
      let index = $(e.currentTarget).index();
      this.refs.chart.chart_instance.data.datasets[index].hidden = !this.refs.chart.chart_instance.data.datasets[index].hidden;
      $(e.currentTarget).toggleClass('disable-legend');
      this.refs.chart.chart_instance.update();
   });
}

UPDATED

After the commect of @Chase DeAnda, I changed a little bit based on his considerations:

// Applying the callback function to the ref
<Line ref={this.applyRef} data={this.convertData(this.props.data)}  options={this.state.options} />

// Inside the method I call the method to insert the legends
applyRef(ref) {
   this.legend = ref;
   this.insertLegends();
}

// Generates the legend and added them to my container element
// Also give them the onClick event
insertLegends() {
   let legends = this.legend.chart_instance.generateLegend();
   this.refs.chartLegendContainer.innerHTML = legends;
   $(this.refs.chartLegendContainer).find('.legend-item').on('click', (e) => this.onClickLegend(e));
}

// During onClick I update the chart
onClickLegend(e) {
   let index = $(e.currentTarget).index();
   this.legend.chart_instance.data.datasets[index].hidden = !this.legend.chart_instance.data.datasets[index].hidden;
   $(e.currentTarget).toggleClass('disable-legend');
   this.legend.chart_instance.update();
}

Upvotes: 0

Chase DeAnda
Chase DeAnda

Reputation: 16441

If you give the ref a callback, then you won't get a value of null. Doing an inline ref like this causes the first render to be null and then the second render will have the element.

So you should change your refs to:

applyRef(ref) {
    this.legend = ref;
}

render() {
    return (
        // Chart component
        <Line ref={this.applyRef}
              data={this.state.chart}
              options={this.state.options}
        />
    )
}

For adding a click event handler, if you can't add an onClick attrib for some reason, then you can set it in your insertLegends method:

handleClick(e) {
    // Do something here...
}

insertLegends(chart) {
    this.refs.chartLegendContainerGlobal.innerHTML = chart.chart_instance.generateLegend();
    this.refs.chartLegendContainerGlobal.addEventListener('click', this.handleClick);
}

Upvotes: 1

Related Questions