101
Views
10
Comments
Solved
[OutSystems Data Grid] Adding Search and Select All Options to Columns Menu
outsystems-data-grid
Reactive icon
Forge asset by OutSystems
Application Type
Reactive


Hi everyone,

I’m working on a requirement where, when a user clicks the Columns menu option, we need to provide them with both a Search option and a “Select All” feature.

Is it possible to implement these features using OutSystems Forge components? If so, could you offer any suggestions or insights on how to achieve this?

Any advice would be greatly appreciated!

Thank you!


2022-11-12 11-28-30
Gonçalo Martins
Staff
Solution

Hi @Sathish Kumar 

Take a look at this post that can give you a good starting point.

Cheers,
GM

2022-11-12 11-28-30
Gonçalo Martins
Staff

Hello @Sathish Kumar 

To have the community help please share an oml with your use case and what you have already tried to make it more collaborative and efficient.
Also, try to check on Wijmo's Flexgrid website if the use case is possible and share an example so it can be easier to adapt. 


Cheers,
GM

2026-02-16 06-54-31
Sathish Kumar

Hi @Gonçalo Martins I don't have any OML for this. A new requirement from the client is that they want both a "Select All" option and a "Search" function in the column picker. above image was mockup screenshot and found a related script for the  Select All  feature, but I’m having trouble implementing it. Could you help me with this? 


Thanks,

Sathish R

2026-02-16 06-54-31
Sathish Kumar

Could someone please assist me? 

Thanks,

Sathish R

2022-11-12 11-28-30
Gonçalo Martins
Staff
Solution

Hi @Sathish Kumar 

Take a look at this post that can give you a good starting point.

Cheers,
GM

2026-02-16 06-54-31
Sathish Kumar


Hi @Gonçalo Martins 

The script was working well in standard scenarios, but I've run into an issue when grouping columns. Specifically, when grouping columns in an existing grid, the grouped columns are removed and then re-added according to the new grouping in the ColumnPicker.
The problem I’m facing now is that, with the current script, all columns are always visible. When I click Select All, even the grouped columns appear, which is not the desired behavior.

Do you have any suggestions or solutions for this issue?
Here I attached OML and GIF
Thanks in advance! 

2026-02-16 06-54-31
Sathish Kumar


Hi @Gonçalo Martins 

The script was working well in standard scenarios, but I've run into an issue when grouping columns. Specifically, when grouping columns in an existing grid, the grouped columns are removed and then re-added according to the new grouping in the ColumnPicker.
The problem I’m facing now is that, with the current script, all columns are always visible. When I click Select All, even the grouped columns appear, which is not the desired behavior.
Do you have any suggestions or solutions for this issue?Here I attached OML and GIF
Thanks in advance! 

Grid_SelectAll.oml
2026-02-16 06-54-31
Sathish Kumar

Hi @Gonçalo Martins 

Thank you for the solution for the “Select All” functionality. It will be very helpful in my development. I also need a solution for implementing a search option. Do you have any suggestions for that as well?

2022-11-12 11-28-30
Gonçalo Martins
Staff

Hi @Sathish Kumar 

Give it a try based on the other use case since the base is already in place and after that share an oml with your attempts and the parts where you're struggling so it can be more efficient and collaborative for the community instead of asking without trying.

Cheers,
GM

2026-02-16 06-54-31
Sathish Kumar

Hi @Gonçalo Martins
Adding Search to Columns Picker Menu We achieved this. Below Script Both Selectall and search

JS

function createColumnPickerWithSearch() {

    // Create the main container

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

    columnPickerContainer.style.display = 'none';

    columnPickerContainer.classList.add('column-picker-container');


    // Create the column picker element

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

    columnPicker.id = 'theColumnPicker';

    columnPicker.classList.add('column-picker');

    columnPickerContainer.appendChild(columnPicker);


    // Create the search container

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

    searchContainer.classList.add('column-picker-search-container', 'column-picker-data-child');


    // Create the search icon element

//    const searchIcon = document.createElement('i');

//    searchIcon.classList.add('search-icon', 'fa', 'fa-search'); // Example for FontAwesome


    // Create the search input element

    const searchInput = document.createElement('input');

    searchInput.type = 'text';

    searchInput.classList.add('column-picker-search');

    searchInput.placeholder = 'Search';


    //searchContainer.appendChild(searchIcon);

    searchContainer.appendChild(searchInput);


    // Create the column picker data element

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

    columnPickerData.classList.add('column-picker-data', 'wj-listbox-item');

    columnPickerContainer.appendChild(columnPickerData);


    // Create the checkbox and label

    const checkbox = document.createElement('input');

    checkbox.type = 'checkbox';

    checkbox.classList.add('selectChk', 'column-picker-data-child');


    const label = document.createElement('label');

    label.textContent = 'Select All';

    checkbox.classList.add('column-picker-data-child');

    label.style.margin = '0 0 0 4px';

    

    columnPickerData.appendChild(searchContainer);

    columnPickerData.appendChild(checkbox);

    columnPickerData.appendChild(label);


    return columnPickerContainer;

}


var theGrid = OutSystems.GridAPI.GridManager.GetGridById($parameters.GridWidgetId);


if (theGrid) {

    var theColumnPicker = theGrid.features.columnPicker._theColumnPicker;

    var columnsToBeDisplayedOnColumnPicker = theGrid.features.columnPicker._getColumnsToBeDisplayedOnColumnPicker();

    theColumnPicker.itemsSource = columnsToBeDisplayedOnColumnPicker;


    const topLeftCell = theGrid.provider.hostElement.querySelector('.wj-topleft');


    topLeftCell.addEventListener('mousedown', (event) => {

        const target = event.target;

        if (!wijmo.hasClass(target, 'column-picker-icon')) return;


        let spanPrev = theGrid.provider.hostElement.querySelector('.column-picker-icon');

        spanPrev.outerHTML = spanPrev.outerHTML; // This removes all events


        const columnPickerHost = theColumnPicker.hostElement;

        const isColumnPickerVisible = columnPickerHost.offsetHeight > 0;


        if (!isColumnPickerVisible) {

            const alreadyHaveSelectAll = columnPickerHost.querySelector('.column-picker-data') !== null;

            const elemSelectAll = alreadyHaveSelectAll ? columnPickerHost.querySelector('.column-picker-data') : createColumnPickerWithSearch();

            const columnPickerDataElement = elemSelectAll.querySelector('.column-picker-data');


            if (columnPickerDataElement && !alreadyHaveSelectAll) {

                const selectCheckbox = columnPickerDataElement.querySelector('.selectChk');

                selectCheckbox.checked = true;


                columnPickerHost.insertBefore(columnPickerDataElement, columnPickerHost.firstChild);


                selectCheckbox.addEventListener('change', (ev) => {

                    const isChecked = ev.target.checked;

                    theColumnPicker.checkedItems = isChecked

                        ? theColumnPicker.collectionView.items

                        : [];

                });


                columnPickerHost.addEventListener('click', (ev) => {

                    // Prevent select all checkbox action if the target is the search input

                    if (ev.target.classList.contains('column-picker-search')) return;


                    const target = ev.target;

                    if (wijmo.closestClass(target, 'column-picker-data') && !wijmo.hasClass(target, 'selectChk')) {

                        if (selectCheckbox.indeterminate) {

                            selectCheckbox.indeterminate = false;

                            selectCheckbox.checked = true;

                            theColumnPicker.checkedItems = theColumnPicker.collectionView.items;

                        } else {

                            selectCheckbox.checked = !selectCheckbox.checked;

                            theColumnPicker.checkedItems = selectCheckbox.checked

                                ? theColumnPicker.collectionView.items

                                : [];

                        }

                    }

                });


                // Add search functionality

                const searchInput = columnPickerHost.querySelector('.column-picker-search');

                searchInput.addEventListener('input', (ev) => {

                    const query = ev.target.value.toLowerCase();

                    filterColumns(query);

                });


                updateSelectAllCheckboxState();

            }


            wijmo.showPopup(columnPickerHost, topLeftCell, false, true, false);

            theColumnPicker.focus();

        } else {

            wijmo.hidePopup(columnPickerHost, true, true);

            theGrid.provider.focus();

        }

        event.preventDefault();

    });

}


function filterColumns(query) {

    const columnPickerHost = document.getElementById('theColumnPicker');

    const columnItems = columnPickerHost.querySelectorAll('.wj-listbox-item:not(.column-picker-data)');


    columnItems.forEach(item => {

        const label = item.querySelector('label').textContent.toLowerCase();

        item.style.display = label.includes(query) ? '' : 'none';

    });

}


function updateSelectAllCheckboxState() {

    var theGrid = OutSystems.GridAPI.GridManager.GetGridById($parameters.GridWidgetId);

    if (!theGrid) return;


    var theColumnPicker = theGrid.features.columnPicker._theColumnPicker;

    if (!theColumnPicker) return;


    var checkedItemsCount = theColumnPicker.checkedItems.length;

    var totalColumnsCount = theGrid.features.columnPicker._getColumnsToBeDisplayedOnColumnPicker().length;


    var isSelectAllColumns = (totalColumnsCount === checkedItemsCount);


    var selectAllCheckbox = theColumnPicker.hostElement.querySelector('.selectChk');

    if (!selectAllCheckbox) return;


    selectAllCheckbox.checked = isSelectAllColumns;

    selectAllCheckbox.indeterminate = false; // Ensure it's not in indeterminate state

}


function addCheckboxChangeListener() {

    var theGrid = OutSystems.GridAPI.GridManager.GetGridById($parameters.GridWidgetId);

    if (!theGrid) return;


    var theColumnPicker = theGrid.features.columnPicker._theColumnPicker;

    if (!theColumnPicker) return;


    var selectAllCheckbox = theColumnPicker.hostElement.querySelector('.selectChk');

    if (!selectAllCheckbox) return;


    theColumnPicker.collectionView.collectionChanged.addHandler(() => {

        updateSelectAllCheckboxState();

    });

}


addCheckboxChangeListener();



CSS

.wj-listbox.column-picker {
  display: grid;
  grid-template-columns: repeat(1, 1fr);
  grid-gap: 0 10px;
  columns: 1; /* IE fallback */
  padding: 12px;
  margin-left: 12px;
  margin-top: 26px;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
.wj-listbox .wj-listbox-item > label {
  display: block;
  margin: 0 0 3px 0;
}
.wj-listbox .wj-listbox-item.wj-state-selected {
  background: transparent;
  color: inherit;
}
.wj-listbox .wj-listbox-item:hover {
  background: rgba(0, 0, 0, 0.05);
}
.wj-listbox .drop-marker {
  position: absolute;
  background: #0085c7;
  opacity: 0.5;
  pointer-events: none;
  z-index: 1000;
}
.column-picker-data {
    padding: 4px 6px 3px 6px !important;
    display: flex;
    flex-wrap: wrap;
    max-width: 190px;
}

.column-picker-data .selectChk {
    margin: 4px;
}

.column-picker-data-child {
    flex: 0 1 auto;
}

.column-picker-data-child:nth-child(1) {
    flex-basis: 100%;
}

.column-picker-search-container {
    margin-bottom: 8px;
    display: flex; /* Ensure proper alignment of the icon and input */
    align-items: center;
}

.search-icon {
    margin-right: 8px; /* Space between the icon and the input */
    font-size: 16px; /* Size of the icon */
    color: #888; /* Color of the icon */
}

.column-picker-search {
    border-color: var(--color-primary) !important;
    height: 30px;
    padding-left: 10px; /* Ensure padding accommodates the icon */
    flex: 1; /* Ensure the input takes up remaining space */
    width: 100px;
}

2026-02-16 06-54-31
Sathish Kumar

Hi @Gonçalo Martins 

The script was working well in standard scenarios, but I've run into an issue when grouping columns. Specifically, when grouping columns in an existing grid, the grouped columns are removed and then re-added according to the new grouping in the ColumnPicker.
The problem I’m facing now is that, with the current script, all columns are always visible. When I click Select All, even the grouped columns appear, which is not the desired behavior.

Do you have any suggestions or solutions for this issue?

Thanks in advance! 

Grid_SelectAll.oml
Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.