Customizing Joget Spreadsheet Elements
The native Spreadsheet Element in Joget DX offers a powerful way to manage tabular data within forms, mimicking the familiar interface of spreadsheet software. Out of the box, however, its columns are limited to basic text inputs or dropdown selections. This restricts the ability to embed dynamic functionality directly into the data grid. For developers needing to add row-specific actions, such as a delete button, or transform static text into interactive elements like modal popup links, Joget DX allows for the integration of custom Handsontable renderer functions directly within the Spreadsheet column properties.
This capability unlocks richer user experiences and more efficient data management workflows. Instead of relying on separate buttons or links outside the grid, users can interact with data points directly within the spreadsheet interface. This guide explores two practical applications of custom cell renderers: implementing a row-deletion button and creating interactive drill-down links.
Example 1: Adding a Custom Row-Deletion Button
To incorporate a delete button for each row in your Joget Spreadsheet, you need to define a custom renderer function. Navigate to the Spreadsheet element within your Joget form builder. Select the specific column where you want the action buttons to appear. Within the column's properties, locate the option for a custom renderer function. Here, you will input a JavaScript function that Handsontable will use to render the cells in that column.
The function needs to instruct Handsontable on how to draw the content for each cell. For a delete button, this involves creating a button element and appending it to the cell. Crucially, this button must also have an event listener attached to trigger the row deletion logic when clicked. The renderer function typically receives arguments like the cell's DOM element, its row and column coordinates, and the cell's value. You can use these to identify the specific row to be deleted and then call the appropriate Joget API or JavaScript function to remove that row from the spreadsheet data model.
Consider the following structure for the custom renderer:
function(instance, td, row, col, prop, value, cellProperties) {
Handsontable.Dom.empty(td);
td.style.textAlign = 'center';
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.className = 'btn btn-danger btn-sm'; // Bootstrap classes for styling
deleteButton.addEventListener('click', function() {
// Joget's Spreadsheet element uses Handsontable internally.
// You can access the Handsontable instance via the element's API.
// Assuming 'spreadsheetElement' is the ID of your Joget Spreadsheet element.
const spreadsheet = $('#' + instance.container.id).data('joget-spreadsheet');
if (spreadsheet) {
spreadsheet.removeRow(row);
} else {
// Fallback for direct Handsontable access if needed, though less common in Joget context.
instance.alter('remove_row', row);
}
});
td.appendChild(deleteButton);
return td;
}
This code snippet first clears any existing content in the table data (td) cell. It then creates a new button element, sets its text to 'Delete', and applies Bootstrap classes for styling. An event listener is attached to this button. When clicked, it accesses the Joget Spreadsheet instance associated with the Handsontable element and calls its removeRow method, passing the current row index. This ensures that the correct row is removed from the data model and the UI is updated accordingly. The instance.container.id correctly refers to the DOM element ID of the Handsontable instance, which is usually the same as the Joget Spreadsheet element's ID.

Example 2: Rendering Interactive Modal Popup Links
Another common requirement is to transform plain text data within a cell into an interactive link that triggers a modal popup, perhaps to display more detailed information or an edit form for that specific record. This enhances data exploration and editing capabilities without cluttering the main spreadsheet view.
Similar to the delete button, this involves defining a custom Handsontable renderer. The function will create an anchor (<a>) tag. The text of the link could be the cell's current value, or a generic label like 'View Details'. The key is to attach an event listener to this link that, when clicked, will trigger the display of a Joget modal. This modal can be configured to load a specific form or content relevant to the clicked row's data.
Here’s how you might implement such a renderer:
function(instance, td, row, col, prop, value, cellProperties) {
Handsontable.Dom.empty(td);
td.style.textAlign = 'left';
const link = document.createElement('a');
link.textContent = value || 'View Details'; // Use cell value or default text
link.href = '#'; // Prevent default anchor behavior
link.style.color = '#007bff'; // Example styling
link.style.cursor = 'pointer';
link.addEventListener('click', function(event) {
event.preventDefault(); // Stop the browser from navigating
// Assuming 'openModal' is a JavaScript function available in your Joget page context
// that opens a modal and can receive parameters like row data.
// You might need to pass the current row's data or an ID to identify it.
const rowData = instance.getSourceDataAtRow(row);
// Example: openModal('myModalId', { recordId: rowData.id, otherData: '...' });
// Or more generically, trigger a Joget UI event.
console.log('Opening modal for row:', row, 'with data:', rowData);
// Replace this console log with your actual modal opening logic.
// For Joget DX, you might use joget.openModal() or similar functions
// if available in the global scope or via component APIs.
// A common pattern is to trigger a custom event or call a specific Joget function
// For instance, if you have a button elsewhere that opens a modal with a specific record:
// const targetButton = document.getElementById('open-detail-modal-button');
// if (targetButton) {
// targetButton.dataset.recordId = rowData.id; // Set data attribute
// targetButton.click(); // Trigger the button click
// }
});
td.appendChild(link);
return td;
}
In this example, the renderer creates an anchor tag. If the cell has a value, it's used as the link text; otherwise, 'View Details' is displayed. The href is set to '#' to prevent page jumps, and basic styling is applied. The crucial part is the event listener. It prevents the default anchor behavior using event.preventDefault(). Then, it retrieves the data for the entire row using instance.getSourceDataAtRow(row). This data can then be used to populate the modal or identify the record for which the modal should be opened. The example includes comments suggesting how to integrate this with Joget's modal functionalities, which might involve calling a global JavaScript function like joget.openModal() or triggering an event that a parent component listens for.

Integrating Custom Renderers
To implement these custom renderers within Joget DX:
- Edit the form containing the Spreadsheet element.
- Select the Spreadsheet element to open its properties.
- For each column you wish to customize, find the 'Column Properties' or similar section.
- Locate the 'Renderer Function' or 'Custom Renderer' property.
- Paste the JavaScript code for your desired renderer into the provided text area.
- Save the form and preview it to test the functionality.
It's important to ensure that the JavaScript code is syntactically correct and that any Joget-specific functions or IDs used (like joget.openModal or element IDs) are correctly referenced within your application's context. Debugging can be done using the browser's developer console, inspecting the table elements and logging values from within the renderer functions.
Broader Implications
The ability to inject custom renderers into Joget's Spreadsheet element significantly expands its utility beyond basic data entry. It allows for the creation of highly interactive and user-friendly interfaces for complex data management tasks. Developers can now build applications with more sophisticated data grids that incorporate direct manipulation actions and contextual information display, streamlining user workflows and reducing the need for external UI components. This flexibility empowers users to manage data more efficiently, directly within the form context, making Joget DX a more robust platform for custom application development.
