Empty table generated in Salesforce Lightning Web component

Tags: #<Tag:0x00007efc6b694970>

I’m trying to get handsonTable implemented in a salesforce lightning web component.
I understand that the audience here might not have Salesforce knowledge, but hoping to work together to find out what the problem could be.

Below is a very basic implementation taken from the examples, but extremely simplified.

<html>

<head>
	<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/handsontable@latest/dist/handsontable.full.min.css">
	<link rel="stylesheet" type="text/css" href="https://handsontable.com/static/css/main.css">
	<script src="https://cdn.jsdelivr.net/npm/handsontable@latest/dist/handsontable.full.min.js"></script>
</head>

<body>
	<div id="hot"></div>
	<script>
		var dataObject = [{
			id: 1,
			currency: 'Euro'
		}, {
			id: 2,
			currency: 'Japanese Yen'
		}];
		var hotElement = document.querySelector('#hot');
		var hotElementContainer = hotElement.parentNode;
		var hotSettings = {
			data: dataObject,
			columns: [{
				data: 'id',
				type: 'numeric',
				width: 40
			}, {
				data: 'currency',
				type: 'text'
			}],
			rowHeaders: true,
			colHeaders: [
				'ID',
				'Currency'
			]
		};
		var hot = new Handsontable(hotElement, hotSettings);
	</script>
</body>

</html>

In order to use external libraries in Salesforce Lightning Web Components (LWC), I am using the format mentioned in https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.create_third_party_library

Modifying the HTML code above to the format mentioned gives me the LWC JS file as

import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import handsonTableResource from '@salesforce/resourceUrl/handsonTable';

export default class handsonTable extends LightningElement {
	dataObject = [
		{
		  id: 1,
		  currency: 'Euro'
		},
		{
		  id: 2,
		  currency: 'Japanese Yen'
		}
	];

	renderedCallback() {
		Promise.all([
			loadScript(this, handsonTableResource + '/handsontable.full.js'),
			loadStyle(this, handsonTableResource + '/handsontable.full.css')
		])
		.then(() => {
			this.initialiseHandsOnTable();
		})
		.catch(error => {
			alert(error);
		});
	}

	hotElement;
	hotSettings;
	initialiseHandsOnTable() {
		this.hotElement = this.template.querySelector('div.hotElement');
		this.hotSettings = {
			data: this.dataObject,
			columns: [
				{
					data: 'id',
					type: 'numeric',
					width: 40
				},
				{
					data: 'currency',
					type: 'text'
				}
			],
			rowHeaders: true,
			colHeaders: [
				'ID',
				'Currency'
			]
		};
		new Handsontable(this.hotElement, this.hotSettings);
	}
}

and the LWC html as

<template>
	<div class="slds-m-around_medium">
		<div class="hotElement" lwc:dom="manual"></div>
	</div>
</template>

Applying these, gives me the result as below in Salesforce

The DOM generated is as below

<c-handson-table data-data-rendering-service-uid="188" data-aura-rendered-by="322:0">
	<div class="slds-m-around_medium">
		<div class="hotElement handsontable htRowHeaders htColumnHeaders" id="ht_917e38abdce11495">
			<div class="ht_master handsontable" style="position: relative; overflow: visible;">
				<div class="wtHolder" style="position: relative; overflow: visible;">
					<div class="wtHider">
						<div class="wtSpreader" style="position: relative;">
							<table class="htCore">
								<colgroup></colgroup>
								<thead>
									<tr></tr>
								</thead>
								<tbody></tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
			<div class="ht_clone_top handsontable" style="position: absolute; top: 0px; left: 0px; overflow: hidden;">
				<div class="wtHolder" style="position: relative;">
					<div class="wtHider">
						<div class="wtSpreader" style="position: relative;">
							<table class="htCore">
								<colgroup></colgroup>
								<thead>
									<tr></tr>
								</thead>
								<tbody></tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
			<div class="ht_clone_bottom handsontable" style="position: absolute; top: 0px; left: 0px; overflow: hidden;">
				<div class="wtHolder" style="position: relative;">
					<div class="wtHider">
						<div class="wtSpreader" style="position: relative;">
							<table class="htCore">
								<colgroup></colgroup>
								<thead>
									<tr></tr>
								</thead>
								<tbody></tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
			<div class="ht_clone_left handsontable" style="position: absolute; top: 0px; left: 0px; overflow: hidden;">
				<div class="wtHolder" style="position: relative;">
					<div class="wtHider">
						<div class="wtSpreader" style="position: relative;">
							<table class="htCore">
								<colgroup></colgroup>
								<thead>
									<tr></tr>
								</thead>
								<tbody></tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
			<div class="ht_clone_top_left_corner handsontable" style="position: absolute; top: 0px; left: 0px; overflow: hidden;">
				<div class="wtHolder" style="position: relative;">
					<div class="wtHider">
						<div class="wtSpreader" style="position: relative;">
							<table class="htCore">
								<colgroup></colgroup>
								<thead>
									<tr></tr>
								</thead>
								<tbody></tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
		</div>
		<div id="hot-display-license-info">The license key for Handsontable is missing. Use your purchased key to activate the product. Alternatively, you can activate Handsontable to use for non-commercial purposes by passing the key: 'non-commercial-and-evaluation'. <a target="_blank" href="https://handsontable.com/docs/tutorial-license-key.html">Read more</a> about it in the documentation or contact us at <a href="mailto:support@handsontable.com">support@handsontable.com</a>.</div>
	</div>
</c-handson-table>

As you can see the DOM structure is being generated for handsonTable but none of the data or columns are being generated.
I do not see any errors or warning on the Chrome Dev Tools console (except the license warning from handson table)

Any assistance would be greatly appreciated.

Hey @jerun.jose

are you able to use any core methods, like getData() or run the afterRender hook?

Hi @aleksandra_budnik,

Thanks for the reply. The code methods seem to function as expected. I am not sure how to add or use the afterRender hook.
One observation I found is that the row count seems to reflect what we see on screen.

a.countRows();
--> 2
a.countEmptyRows();
--> 0
a.countVisibleRows();
--> -1
a.countRenderedRows();
--> -1

I have been able to publish the implementation on a public facing URL. You can access my implementation at https://sandbox-business-java-1763-16aaf9f33bb.cs6.force.com/
I have added a debugger at the start of the initialiseHandsOnTable function to help.

I afraid that we do not have any demos where Handsontable is used inside Salesforce. Did you read this post https://salesforce.stackexchange.com/questions/80511/build-a-time-management-vf-page? It seems helpful.

Thanks @aleksandra_budnik . I have read the stackexchange post and it doesn’t help me with this situation. I suspect the problem could be with Salesforce Locker Service.

Locker service restricts the scope of DOM navigation and manipulation allowed by components.
Debugging the script we found that the isVisible(elem) function was trying to navigate all the way up to the top level HTML node (which was blocked by the Locker Service).
The answer at Handsontable within the Salesforce Locker service helped in fixing this.
After updating the isVisible(elem) to change as below:
next = next.parentNode;
to
if(next.parentNode != null) next = next.parentNode; else return true;

Now, the solution works.

1 Like