Hi,
I am trying to resize all column widths programatically in order to obtain the same result than if a user would do the following actions:
- Select all cells (Ctrl+A)
- Hover a column header until the resize-handle appears
- Double-click on it
But I cannot find the correct method to call. Would you have an idea ?
What I have right now does not work unless I first hover the handle manually. So it is useless to me in this form:
let domID = 'element_HTcontainer_' + element.id;
let handleJquery = $('#' + domID + ' .manualColumnResizer');
let maxSecurity = 0;
while (handleJquery.length <= 0 && maxSecurity < 100) {
handleJquery = $('#' + domID + ' .manualColumnResizer');
maxSecurity++;
}
if (handleJquery && handleJquery.length > 0) {
const handleDom = handleJquery[0];
let sheet = document.styleSheets[0];
if (sheet) {
// Adds CSS rules to hide highlight on headers, cells and borders
let indexHeaders = sheet.insertRule('#' + domID + ` tbody th.ht__active_highlight, .handsontable thead th.ht__active_highlight {background: #f0f0f0 !important; opacity: 1;}`);
let indexCells = sheet.insertRule('#' + domID + ` td.area::before {background-color: #fff !important;}`);
let indexBorders = sheet.insertRule('#' + domID + ` .wtBorder {display: none !important;}`);
// Resetting handle
handleDom.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
// 1. Selects all cells
$scope.hots[element.id]?.selectAll();
setTimeout(() => {
// 2. Simulates double-click
for (let i = 0; i < 2; i++) {
handleDom.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: window,
})
);
setTimeout(() => {
handleDom.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
}, 50);
}
setTimeout(() => {
// 3. Deselects all cells
$scope.hots[element.id]?.deselectCell();
// Removes previously introduced CSS rules
sheet?.deleteRule(indexCells);
sheet?.deleteRule(indexHeaders);
sheet?.deleteRule(indexBorders);
}, 500);
}, 150);
}
}
Hi @gregoire.spiers
Do you plan to resize them all with the same width, like here
or set a width for all of the columns based on one of them
Neither.
I want to make use of the manulColumnResize
plugin to adjust each column width depending on data length inside each column. Does that make sense ?
Reformulating: I want to have a button on which the user can click to automatically resize all columns width depending on data inside each columns
A working solution (although feels very hacky…) for now
/**
* Resize all columns width of a given Element.
* Why you would need it: The Handsontable plugin `manualColumnResize` that provides the handle
* which we use to resize a column width does not provide any easy to use
* method to resize all columns. We solve this problem by simulating
* the following user actions:
* 1. Select all cells
* 2. Double-click on the handle
* 3. Deselect all cells
* Hiding css: we do not want the style effects of selecting cells.
* @param {Element} element A ListElement or MatrixElement
*/
$scope.autoResizeColumnsWidth = function (element) {
if (element?.type != 'Matrix' && element?.type != 'List') {
throw new Error('Bad Element type');
}
const getHandle = function (domID) {
let colHeaders = document.getElementById(domID).querySelectorAll('.ht_clone_top thead th');
for (let header of colHeaders) {
setTimeout(() => {
header.dispatchEvent(
new MouseEvent('mouseover', {
bubbles: true,
cancelable: true,
view: window,
})
);
}, 50);
}
let hdle = document.getElementById(domID).getElementsByClassName('manualColumnResizer');
if (hdle.length > 0) {
return hdle[0];
}
};
setTimeout(() => {
const domID = 'element_HTcontainer_' + element.id;
let handle = getHandle(domID);
if (handle) {
let sheet = document.styleSheets[0];
if (sheet) {
// Adds CSS rules to hide highlight on headers, cells and borders
let indexHeaders = sheet.insertRule('#' + domID + ` tbody th.ht__active_highlight, .handsontable thead th.ht__active_highlight {background: #f0f0f0 !important; opacity: 1;}`);
let indexCells = sheet.insertRule('#' + domID + ` td.area::before {background-color: #fff !important;}`);
let indexBorders = sheet.insertRule('#' + domID + ` .wtBorder {display: none !important;}`);
// Resetting handle
handle.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
// 1. Selects all cells
$scope.hots[element.id]?.selectAll();
setTimeout(() => {
// 2. Simulates double-click
for (let i = 0; i < 2; i++) {
handle.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: window,
})
);
handle.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
}
setTimeout(() => {
// 3. Deselects all cells
$scope.hots[element.id]?.deselectCell();
// Removes previously introduced CSS rules
sheet?.deleteRule(indexCells);
sheet?.deleteRule(indexHeaders);
sheet?.deleteRule(indexBorders);
}, 250);
}, 50);
}
}
}, 500);
};
By default column expands with the text. But when you attach colWidths
or colWith
(via columns
) autoColumnSize
plugin is disabled.
At the moment there is no API to get back to those auto-resized columns so if you found a workaround than I’m more than happy to hear that it works for you. This is how we handled the db-click within the plugin https://github.com/handsontable/handsontable/blob/2dbc605c14b4f13eb25b77679f1c1cab98a274ad/handsontable/src/plugins/manualColumnResize/manualColumnResize.js#L404
Thank you, an API with a simple call would have been a lot easier indeed…
Anyway, if someone needs this feature, here is my workaround “as-is” :
$scope.autoResizeColumnsWidth = function (element, retry = true) {
element.resizeInProgress = true;
if (element?.type != 'Matrix' && element?.type != 'List') {
throw new Error('Bad Element type');
}
const domID = 'element_HTcontainer_' + element.id;
const getHandle = function () {
let colHeaders = document.getElementById(domID).querySelectorAll('.ht_clone_top thead th');
for (let header of colHeaders) {
$timeout(() => {
header.dispatchEvent(
new MouseEvent('mouseover', {
bubbles: true,
cancelable: true,
view: window,
})
);
}, 50);
}
let hdle = document.getElementById(domID).getElementsByClassName('manualColumnResizer');
if (hdle.length > 0) {
return hdle[0];
}
};
$timeout(() => {
let handle = getHandle();
if (handle) {
let sheet = document.styleSheets[0];
if (sheet) {
// Adds CSS rules to hide highlight on headers, cells and borders
let indexHeaders = sheet.insertRule('#' + domID + ` tbody th.ht__active_highlight, .handsontable thead th.ht__active_highlight {background: #f0f0f0 !important; opacity: 1;}`);
let indexCells = sheet.insertRule('#' + domID + ` td.area::before {background-color: #fff !important;}`);
let indexBorders = sheet.insertRule('#' + domID + ` .wtBorder {display: none !important;}`);
// Resetting handle
handle.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
// 1. Selects all cells
$scope.hots[element.id]?.selectAll();
$timeout(() => {
// 2. Simulates double-click
for (let i = 0; i < 2; i++) {
handle.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: window,
})
);
handle.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
})
);
}
$timeout(() => {
// 3. Deselects all cells
$scope.hots[element.id]?.deselectCell();
element.resizeInProgress = false;
// Removes previously introduced CSS rules
sheet?.deleteRule(indexCells);
sheet?.deleteRule(indexHeaders);
sheet?.deleteRule(indexBorders);
}, 750);
}, 50);
}
} else {
if (retry) {
$scope.autoResizeColumnsWidth(element, false);
} else {
element.resizeInProgress = false;
}
}
}, 700);
};
1 Like