Programatically resize all columns width

Tags: #<Tag:0x00007efc626037d0>

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:

  1. Select all cells (Ctrl+A)
  2. Hover a column header until the resize-handle appears
  3. 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