Dynamically load dropdown ,

Tags: #<Tag:0x00007efc6d8b6738> #<Tag:0x00007efc6d8b56f8>

dynamically loaded data while changing input value . after selecting dropdown value not able to select the next dropdown … and i want the symbol down icon bold color

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Handsontable with Dynamic Dropdown</title>

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable@8.4.0/dist/handsontable.full.min.css">

<style>

    body, html {

        margin: 0;

        padding: 0;

        height: 100%;

        overflow: hidden;

        font-family: Arial, sans-serif;

        background-color: #f1f1f1;

    }

    .handsontable-container {

        width: 100vw;

        height: calc(100vh - 50px);

        box-sizing: border-box;

    }

    .search-container, .save-container {

        padding: 10px;

        background-color: #ffffff;

    }

    .htDropdown {

    white-space: nowrap; /* Prevent text wrapping */

    overflow: visible; /* Ensure dropdown content is fully visible */

    min-width: 150px; /* Set a minimum width */

    box-sizing: border-box; /* Include padding and border in the element's total width */

}

</style>
<div class="search-container">

    <input type="text" id="search-input" class="form-control" placeholder="Search...">

</div>

<div class="save-container">

    <button id="save-button" class="btn btn-primary" disabled>Save</button>

</div>

<div class="container">

    <button id="export-button" class="btn btn-primary mb-3">Export to Excel</button>

   

</div>

<div id="handsontable-container" class="handsontable-container"></div>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/handsontable@8.4.0/dist/handsontable.full.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js"></script>

<script>

const container = document.getElementById('handsontable-container');

const searchField = document.getElementById('search-input');

const saveButton = document.getElementById('save-button');

let hot;

let originalData = [];

let changedRows = {};

function initHandsontable(headers, data) {

    originalData = JSON.parse(JSON.stringify(data));

     

    hot = new Handsontable(container, {

        data: data,

        colHeaders: headers,

        rowHeaders: true,

        minCols: 50,

        minRows: 100,

        stretchH: 'all',

        autoWrapRow: true,

        width: container.clientWidth,

        height: container.clientHeight,

        contextMenu: true,

        manualColumnResize: true,

        manualRowResize: true,

        licenseKey: 'non-commercial-and-evaluation',

        colWidths: 100,

        rowHeights: 30,

        afterChange: function (changes, source) {

            if (source === 'loadData') return;

            detectChanges(changes);

            changes.forEach(([row, col, oldValue, newValue]) => {

                if (col === 1) { // Assuming column index 1 is where the dropdown is

                     console.log(row)

                    handleDropdownSelection(row, newValue);

                }

                if(col===4 || col===5 || col===6 || col===7)

            {

                 

                var nos=this.getDataAtCell(row,4).split('X');

                var len=this.getDataAtCell(row,5);

                    if(len==null){len=1;}

                var bre=this.getDataAtCell(row,6);

                    if(bre==null){bre=1;}

                var hei=this.getDataAtCell(row,7);

                    if(hei==null){hei=1;}

                   

                    var qu=parseFloat(len)*parseFloat(bre)*parseFloat(hei) * parseFloat(nos[0])* parseFloat(nos[1]);

                    console.log(parseFloat(qu))

                    this.setDataAtCell(row,8,parseFloat(qu))

                 

                console.log(newValue)

               

            }

            });

        },

        cells: function (row, col) {

            const cellProperties = {};

            if (col === 1) { // Assuming column index 1 is where we need to fetch dropdown options

                cellProperties.type = 'dropdown';

               

                cellProperties.source = function(query, process) {

                    fetchDropdownOptions(query).then(data => {

                        const maxOptionWidth = calculateMaxOptionWidth(data);

                        setDropdownWidth(maxOptionWidth);

                        process(data);

                        adjustDropdowns();

                    }).catch(error => {

                        console.error('Error fetching dropdown options:', error);

                        process([]);

                    });

                };

            }

           

            return cellProperties;

        },

        contextMenu: {

        items: {

            "pasteValues": {

                name: 'Paste Column Values',

                callback: function() {

                    var selected = hot.getSelected(); // Get the selected range

                    if (selected && selected.length > 0) {

                        var col = selected[0][1]; // Get the column index

                        var values = [];

                        var lastRow = hot.countRows() - 1;

                        // Get values from the selected column

                        for (var i = 0; i < lastRow; i++) {

                            values.push(hot.getDataAtCell(i, col));

                        }

                        // Insert values into the next row

                        for (var j = 0; j < values.length; j++) {

                            hot.setDataAtCell(lastRow + 1, col, values[j]);

                        }

                    } else {

                        alert('Please select a column to copy values from.');

                    }

                }

            }

        }

    }

       

    });



    function handleDropdownSelection(row, selectedValue) {

    // Get headers

    const headers = hot.getColHeader();

    var myArray=[];

    myArray = selectedValue.split(",");

        console.log(myArray)

   

    //headers.forEach((header, col) => {

        //console.log(header)

        // For example, update cells in columns with a header containing 'Update'

        //if (header.includes('item_code')) {

            hot.setDataAtCell(row, 2, myArray[1]);

        //}

        //if (header.includes('project_name')) {

            //hot.setDataAtCell(row, 1, myArray[0]);

        //}

    //});

}

    function setDropdownWidth(width) {

requestAnimationFrame(() => {

    const dropdowns = document.querySelectorAll('.handsontableEditor'); // Verify this selector in your browser

    dropdowns.forEach(dropdown => {

        dropdown.style.width = `${width + 20}px`; // Adding padding

        dropdown.style.overflow = 'visible'; // Ensure dropdown text is not truncated

    });

    const dropdowns1 = document.querySelectorAll('.handsontable.listbox .ht_master table'); // Verify this selector in your browser

    dropdowns1.forEach(dropdown => {

        dropdown.style.width = `${width + 20}px`; // Adding padding

        dropdown.style.overflow = 'visible'; // Ensure dropdown text is not truncated

    });

});

}

function adjustDropdowns() {

const dropdowns = document.querySelectorAll('.handsontableEditor'); // Verify this selector

 

dropdowns.forEach(dropdown => {

    const options = dropdown.querySelectorAll('.handsontable.listbox .ht_master table tr td');

     

    let maxWidth = 0;

    options.forEach(option => {

        const width = option.clientWidth;

         

        if (width > maxWidth) {

            maxWidth = width;

        }

    });

    setDropdownWidth(maxWidth);

});

}

hot.addHook(‘afterRender’, function() {

adjustDropdowns(); // Adjust dropdown width after rendering

});

hot.addHook(‘afterChange’, function(changes, source) {

if (source === 'loadData') return;

adjustDropdowns(); // Adjust dropdown width after data changes

});

window.addEventListener('resize', function () {

        hot.updateSettings({

            width: container.clientWidth,

            height: container.clientHeight

        });

    });

}

function calculateMaxOptionWidth(options) {

    let maxWidth = 0;

    const dummyDiv = document.createElement('div');

    dummyDiv.style.visibility = 'hidden';

    dummyDiv.style.position = 'absolute';

    dummyDiv.style.whiteSpace = 'nowrap'; // Prevent text wrapping

    dummyDiv.style.padding = '5px'; // Add padding to match dropdown

    document.body.appendChild(dummyDiv);

    options.forEach(option => {

        dummyDiv.textContent = option;

        const width = dummyDiv.offsetWidth;

        if (width > maxWidth) {

            maxWidth = width;

        }

    });

    document.body.removeChild(dummyDiv);

    return maxWidth;

}

function setDropdownWidth(width) {

    setTimeout(() => {

        const dropdowns = document.querySelectorAll('.htDropdown');

        dropdowns.forEach(dropdown => {

            dropdown.style.width = `${width + 20}px`; // Adding padding

            dropdown.style.overflow = 'visible'; // Ensure dropdown text is not truncated

        });

    }, 0); // Delay to ensure dropdown is rendered

}

function loadData() {

    $.ajax({

        url: 'fetch_data.php',

        method: 'GET',

        dataType: 'json',

        success: function(response) {

            const headers = response.headers;

            const data = response.data;

            initHandsontable(headers, data);

        },

        error: function(xhr, status, error) {

            console.error('Error fetching data:', status, error);

        }

    });

}

function detectChanges(changes) {

    changes.forEach(([row, col, oldValue, newValue]) => {

        if (!changedRows[row]) {

            changedRows[row] = hot.getDataAtRowProp(row) || hot.getDataAtRow(row);

        }

        changedRows[row][col] = newValue;

        if (col === 1) { // Assuming column index 1 is where we need to fetch dropdown options

            updateDropdownsForRow(row, newValue);

        }

    });

    saveButton.disabled = Object.keys(changedRows).length === 0;

}

function saveDataToServer() {

    $.ajax({

        url: 'save_data.php',

        method: 'POST',

        dataType: 'json',

        contentType: 'application/json',

        data: JSON.stringify({ changedRows: changedRows }),

        success: function(response) {

             

            changedRows = {};

            saveButton.disabled = true;

        },

        error: function(xhr, status, error) {

            console.error('Error saving data:', status, error);

        }

    });

}

function updateDropdownsForRow(row, value) {

    fetchDropdownOptions(value).then(data => {

        const maxOptionWidth = calculateMaxOptionWidth(data);

        setDropdownWidth(maxOptionWidth);

        hot.updateSettings({

            cells: function (r, c) {

                if (r === row && c === 1) { // Update dropdown for the specific row and column

                    return {

                        type: 'dropdown',

                        source: data

                    };

                }

                return {};

            }

        });

        hot.render();

    }).catch(error => {

        console.error('Error updating dropdown options:', error);

    });

}

function fetchDropdownOptions(query) {

    return new Promise((resolve, reject) => {

        $.ajax({

            url: 'fetch_drop_down.php',

            method: 'GET',

            data: { query: query },

            success: function(response) {

                resolve(response);

            },

            error: function(xhr, status, error) {

                reject([]);

            }

        });

    });

}

loadData();

searchField.addEventListener('keyup', function () {

    const search = hot.getPlugin('search');

    search.query(searchField.value);

    hot.render();

});

saveButton.addEventListener('click', function () {

    saveDataToServer();

});

const exportButton = document.getElementById('export-button');

//const exportPlugin = hot.getPlugin('exportFile');

function exportToExcel() {

    const headers = hot.getColHeader(); // Get column headers

    const data = hot.getData(); // Get table data

    // Combine headers and data

    const worksheetData = [headers].concat(data); // Add headers as the first row

    const ws = XLSX.utils.aoa_to_sheet(worksheetData); // Convert to SheetJS format

    const wb = XLSX.utils.book_new(); // Create a new workbook

    XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); // Append the sheet to the workbook

    XLSX.writeFile(wb, 'handsontable_data.xlsx'); // Write the workbook to a file

}

exportButton.addEventListener('click', function () {

    exportToExcel();

});

Hi @manikandansathiya92

Thank you for contacting us. Please share your implementation in a code demo using StackBlitz or jsFiddle, so we can check it and examine the problem.

not able to select next dropdown… dropdown data coming dynamically based on input enter in cells…

after dropdown close , when click next column for dropdown i am getting warning like this

Performance tip: Handsontable rendered more than 1000 visible rows. Consider limiting the number of rendered rows by specifying the table height and/or turning off the “renderAllRows” option.

function initHandsontable(headers, data) {

    originalData = JSON.parse(JSON.stringify(data));

     

    hot = new Handsontable(container, {

        data: data,

        colHeaders: headers,

        rowHeaders: true,

        minCols: 50,

        minRows: 100,

        stretchH: 'all',

        autoWrapRow: true,

        width: container.clientWidth,

        height: container.clientHeight,

        contextMenu: true,

        manualColumnResize: true,

        manualRowResize: true,

        licenseKey: 'non-commercial-and-evaluation',

        colWidths: 100,

        rowHeights: 30,

        afterChange: function (changes, source) {

            if (source === 'loadData') return;

            detectChanges(changes);

            changes.forEach(([row, col, oldValue, newValue]) => {

                if (col === 1) { // Assuming column index 1 is where the dropdown is

                     console.log(row)

                    //handleDropdownSelection(row, newValue);

                }

                if(col===4 || col===5 || col===6 || col===7)

            {

                 

                var nos=this.getDataAtCell(row,4).split('X');

                var len=this.getDataAtCell(row,5);

                    if(len==null){len=1;}

                var bre=this.getDataAtCell(row,6);

                    if(bre==null){bre=1;}

                var hei=this.getDataAtCell(row,7);

                    if(hei==null){hei=1;}

                   

                    var qu=parseFloat(len)*parseFloat(bre)*parseFloat(hei) * parseFloat(nos[0])* parseFloat(nos[1]);

                    console.log(parseFloat(qu))

                    this.setDataAtCell(row,8,parseFloat(qu))

                 

                console.log(newValue)

               

            }

            });

        },

        cells: function (row, col) {

            const cellProperties = {};

            if (col === 1) { // Assuming column index 1 is where we need to fetch dropdown options

                cellProperties.type = 'dropdown';

               

                cellProperties.source = function(query, process) {

                    fetchDropdownOptions(query).then(data => {

                        const maxOptionWidth = calculateMaxOptionWidth(data);

                        setDropdownWidth(maxOptionWidth);

                        process(data);

                        adjustDropdowns();

                    }).catch(error => {

                        console.error('Error fetching dropdown options:', error);

                        process([]);

                    });

                };

            }

           

            return cellProperties;

        },

         contextMenu: {

        items: {

            "pasteValues": {

                name: 'Total',

                callback: function() {

                    var selected = hot.getSelected(); // Get the selected range

                    console.log(selected.length)

                    const selected1 = hot.getSelected() || [];

                      const data = [];



                    if (selected && selected.length > 0) {

                        var row = selected[0];

                       

                        console.log(row[2])

                        var col = selected[0][1]; // Get the column index

                        var values = [];

                        var lastRow = hot.countRows() - 1;

                        for (let i = 0; i < selected1.length; i += 1) {

                            const item = selected1[i];

                            data.push(hot.getData(...item));

                            console.log(data[0])

                        }

                        var sum=0;

                        for(var l=0;l<data[0].length;l++)

                        {

                                console.log(data[0][l][0])

                                sum +=data[0][l][0];

                                console.log(sum)

                        }

console.log(col)

console.log(lastRow+1)

                        // Get values from the selected column

                       

                        // Insert values into the next row

                                                       

                            hot.setDataAtCell(row[2], row[3]+1, sum);

                       

                    } else {

                        alert('Please select a column to copy values from.');

                    }

                },

               

            } ,

            "add_separator": {

                    name: 'Add separator line',

                    callback: function(key, selection) {

                        console.log(key)

                        console.log(selection[0].start.row)

                        addRowSeparator(selection[0].start.row);

                    }

                },

        }

    }

       

    });

    

    function addRowSeparator(row) {

        const rowCount = hot.countCols();

        for (let i = 0; i < rowCount; i++) {

            const cellMeta = hot.getCellMeta(row, i);

            cellMeta.className = 'htRowSeparator';

            hot.render(); // Re-render the table to apply the changes

        }

    }

    function handleDropdownSelection(row, selectedValue) {

    // Get headers

    const headers = hot.getColHeader();

    var myArray=[];

    myArray = selectedValue.split(",");

        console.log(myArray)

   

    //headers.forEach((header, col) => {

        //console.log(header)

        // For example, update cells in columns with a header containing 'Update'

        //if (header.includes('item_code')) {

            hot.setDataAtCell(row, 2, myArray[1]);

        //}

        //if (header.includes('project_name')) {

            //hot.setDataAtCell(row, 1, myArray[0]);

        //}

    //});

}

    function setDropdownWidth(width) {

requestAnimationFrame(() => {

    const dropdowns = document.querySelectorAll('.handsontableEditor'); // Verify this selector in your browser

    dropdowns.forEach(dropdown => {

        dropdown.style.width = `${width + 20}px`; // Adding padding

        dropdown.style.overflow = 'visible'; // Ensure dropdown text is not truncated

    });

    const dropdowns1 = document.querySelectorAll('.handsontable.listbox .ht_master table'); // Verify this selector in your browser

    dropdowns1.forEach(dropdown => {

        dropdown.style.width = `${width + 20}px`; // Adding padding

        dropdown.style.overflow = 'visible'; // Ensure dropdown text is not truncated

    });

});

}

function adjustDropdowns() {

const dropdowns = document.querySelectorAll('.handsontableEditor'); // Verify this selector

 

dropdowns.forEach(dropdown => {

    const options = dropdown.querySelectorAll('.handsontable.listbox .ht_master table tr td');

     

    let maxWidth = 0;

    options.forEach(option => {

        const width = option.clientWidth;

         

        if (width > maxWidth) {

            maxWidth = width;

        }

    });

    setDropdownWidth(maxWidth);

});

}

hot.addHook(‘afterRender’, function() {

adjustDropdowns(); // Adjust dropdown width after rendering

});

hot.addHook(‘afterChange’, function(changes, source) {

if (source === 'loadData') return;

adjustDropdowns(); // Adjust dropdown width after data changes

});

}

  

function fetchDropdownOptions(query) {

    return new Promise((resolve, reject) => {

        $.ajax({

            url: 'fetch_drop_down.php',

            method: 'GET',

            data: { query: query },

            success: function(response) {

                resolve(response);

            },

            error: function(xhr, status, error) {

                reject([]);

            }

        });

    });

}

@manikandansathiya92

I am not able to reproduce the issue with the code you sent. Please, use a sandbox of your choice as I mentioned previously. Otherwise, we will not be able to help.

Hi @manikandansathiya92

is the issue still replicable?