1

I have a created a bar chart using chart js. The chart loads fine but while trying to create a custom tooltip I am encountering the following which I believe is stopping the tooltip from being created:

Invalid usage of "getElementById". DOM query at the document level is forbidden.

This is what I have for my chart config:

            tooltips: {
                enabled: false,
                callbacks: {
                    label: function (tooltipItem, data) {
                        let items = [];
                        data.forEach((item) => {
                            items.push(item);
                        });
                        return `Item: ${items}`;
                    },
                
                },
                
                custom: function (tooltip) {
                    // Tooltip Element
                    // having trouble here since we can't access ids in LWC, only classes 
                    // lws does not allow access to the document object 
                    
                    let tooltipEl = document.getElementById('chartjs-tooltip');
                    console.log('>element: ', tooltipEl);
                    // Create element on first render
                     if (!tooltipEl) {
                        //tooltipEl = this.template.createElement('div');
                        //tooltipEl = document.createElement('div');
                        //tooltipEl.className = 'chartjs-tooltip';
                        //tooltipEl.innerHTML = '<table></table>';
                        //document.body.appendChild(tooltipEl);
                        //this.template.appendChild(chartjs-tooltip)
                   }

                    function getBody(bodyItem) {
                        return bodyItem.lines;
                    }

                    // Set Text
                    if (tooltip.body) {
                        const titleLines = tooltip.title || [];
                        const bodyLines = tooltip.body.map(getBody);
                        console.log('>>bodyLines: ', bodyLines);
                        let innerHtml = '<thead>';
                        titleLines.forEach(function (title) {
                            innerHtml += '<tr><th>' + title + '</th></tr>';
                        });
                        console.log('titleLines:', titleLines);
                        
                    }

                }, 

What I've tried based on this documentation: https://github.com/salesforce/eslint-plugin-lwc/blob/v1.6.2/docs/rules/no-document-query.md

let tooltipEl = self.template.querySelector('.chartjs-tooltip');

I also tried adding a div to the html:

    <div id="barChart" class={chartClass}>
        <div id="chartjs-tooltip">
          <table></table>
        </div>
        <canvas
          class="bar-chart"
          lwc:dom="manual"
        ></canvas>
      </div>

Any help or insight would be greatly appreciated.

1 Answer 1

0

You can't reliably use ID values in LWR, because they are modified to be globally unique. You also can't query from document, as you've found out. Instead, change the div to also be lwc:dom="manual":

<div lwc:dom="manual" class="chartjs-tooltip">
</div>

Then query for the element:

// Assuming that self = this from component
let tooltipEl = self.template.querySelector('.chartjs-tooltip');

innerHTML should work just fine at this point.

Or, an alternative, you could render the entire tooltip in a template, and avoid the risk of DOM injection. Even though any scripts would be safely sandboxed, someone could still insert random styles or elements intentionally or otherwise. It's hard to know without context.

3
  • When I tried that, It appears that it can't identify query selector and I get [Cannot read properties of undefined (reading 'querySelector')] That is why I tried using self but that didn't work either
    – sforg1
    Commented May 9, 2023 at 19:49
  • @sforg1 The problem here is context. Without your surrounding code, it's impossible to tell what's going on. I used the available information that I had. I have used ChartJS successfully before, so I know it's possible, but like many things programming, it's hard to tell unless we have the full picture.
    – sfdcfox
    Commented May 9, 2023 at 20:08
  • would I need to insert the tooltip into the DOM like we do so for the graph? drawBarGraph(barChartConfig) { if (this.barChart) { this.barChart.destroy(); } // Insert chart into DOM const ctx = this.template.querySelector('canvas.bar-chart').getContext('2d'); this.barChart = new window.Chart(ctx, barChartConfig); //const tooltip = this.template.querySelector('div.chartjs-tooltip'; }
    – sforg1
    Commented May 9, 2023 at 20:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .