Multi-select in grid won't allow un-selecting items

Hi there,

I'm trying to allow users to select multiple things from a multiselect in a grid. Currently I have everything working except I cannot un-select values that were already selected before opening the multi-select dropdown.

The data in the field is an array of longs. The datasource for the multi-select has both numeric IDs and strings for display.


Here is my definition for the column in the grid:

<e-grid-columns>

<e-grid-column headerText="Header name" columns="@(

                        new Syncfusion.EJ2.Grids.GridColumn{

                            Field="TradeIds",

                            HeaderText="TRADE2",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit=new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            Width="200",

                        }

                </e-grid-column>

            </e-grid-columns>


And the JS functions to populate the grid are these:

        let tradeGridElem;

        let tradeSelectObj;


        function tradeCreate(args) {

            tradeGridElem = document.createElement('input');

            return tradeGridElem;

        }


        function tradeRead() {

            return tradeSelectObj.value;

        }


        function tradeWrite(args) {

            tradeSelectObj = new ej.dropdowns.MultiSelect({

                dataSource: @Html.Raw(Json.Serialize(Model.Contractors)),

                fields: { text: 'Text', value: 'Value' },

                value: args.rowData[args.column.field],

                mode: 'CheckBox',

                width: 120,

                popupWidth: 300,

                hideSelectedItem: false,

                enableSelectionOrder: false

            });

            tradeSelectObj.appendTo(tradeGridElem);

        }


        function tradeDestroy() {

            tradeSelectObj.destroy();

        }



So when I open the dropdown, the values listed as selected are checked in the dropdown list, which is good, but clicking on the checkbox does nothing. See this image, where "BMW" is listed as the selected value, but clicking on that checkbox does absolutely nothing. Clicking on the "X" to clear also does nothing.




Clicking on any of the other checkboxes selects and then unselects them, as expected. However, as soon as the dropdown is closed and the record is saved, any newly selected boxes also become unresponsive.

What do I need to change to be able to uncheck these boxes without breaking anything else? 


22 Replies

KV Katherine Valentine March 29, 2022 08:55 PM UTC

Actually, there is one other issue: the filter shows the IDs instead of the text values. I see there is something called a "FilterTemplate" in Blazor, but I can't find any reference to it in the documentation for the .NET CORE controls. How can I customize the filters?



RS Rajapandiyan Settu Syncfusion Team March 30, 2022 10:53 AM UTC

Hi Katherine,


Thanks for contacting Syncfusion support.


We have prepared a sample based on your requirement. In which we have rendered the MultiSelect component using cellEditTemplate feature of Grid. Find the below documentation for more information.


cellEditTemplate: https://ej2.syncfusion.com/aspnetcore/documentation/grid/editing/edit-types#custom-editors-using-template

MultiSelect: https://ej2.syncfusion.com/javascript/documentation/multi-select/es5-getting-started/


The EJ2 Grid column does not support the array type of value. So, we have maintained the multiselect values in string format and separated by comma.


 

[index.cshtml]

 

<ejs-grid id="Grid" dataSource="@ViewBag.DataSource" toolbar="@(new List<string>() { "Add", "Edit", "Delete","Update","Cancel" })">

    <e-grid-editSettings allowAdding="true" allowDeleting="true" allowEditing="true" mode="Normal"></e-grid-editSettings>

        <e-grid-columns>

            <e-grid-column headerText="Order Details" columns="@( new List<Syncfusion.EJ2.Grids.GridColumn>() { new Syncfusion.EJ2.Grids.GridColumn{

                            Field="ShipCountry",

                            HeaderText="ShipCountry",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit=new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            Width="220",

                        }})">

            </e-grid-column>

 

        </e-grid-columns>

</ejs-grid>

 

<script>

    var multiSelectObj;

    function tradeCreate(args) {

        var elem = document.createElement('input');

        return elem;

    }

    function tradeWrite(args) {

        // split the cell value by comma

      var cellvalue = args.rowData[args.column.field] ? args.rowData[args.column.field].split(',') : [];

      multiSelectObj = new ej.dropdowns.MultiSelect({

        //set the data to dataSource property

        dataSource: @Html.Raw(Json.Serialize(ViewBag.DataSource)),

        fields: { text: 'ShipCountry', value: 'ShipCountry' },

        value: cellvalue, // bind the value in array format

        mode: 'CheckBox',

        popupWidth: 300,

        hideSelectedItem: false,

        enableSelectionOrder: false,

      });

      multiSelectObj.appendTo(args.element);

    }

 

    function tradeDestroy() {

        multiSelectObj.destroy();

    }

    function tradeRead(args) {

        // join the value by comma

        return multiSelectObj.value.join(','); // store the string value in the Grid dataSource

    }

</script>

 


Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/core_3_grid_multiselect_edit1341039769.zip


Query #2: there is one other issue: the filter shows the IDs instead of the text values.


Kindly share the below details to proceed further on this.


  1. Is your requirement to perform data action on one field and show another field value in Grid?
  2. What is your requirement explain in detail?
  3. Share the video demo of your requirement.


Regards,

Rajapandiyan S



KV Katherine Valentine March 30, 2022 03:28 PM UTC

Rajapandiyan,


Thanks for your response. My underlying data was already an array, but upon closer inspection, the dropdown datasource was actually a string instead of a number. Changing the types to match fixed the issue. It would be a nice improvement if Syncfusion components would throw some kind of error in that situation rather than failing silently.


As for the filter, I will probably need to completely customize how it behaves, since the grid doesn't support arrays. Right now, the filter looks like this:



There are two issues here: one, it's showing the numeric ID rather than the text value. Two, it's showing them grouped together rather than separately. Instead, I would like the filter dropdown to match my multi-select list, and for it to display all records which have any of the selected values associated with it. For example, let's say ID #7 is Belgium. I want Belgium to show up in the list as an individual item, and if it is checked, I want the records with the arrays "7,1,3" and "1,7,8" to be displayed, since they both include Belgium (id #7). 

I don't need a complete example of how to do all that logic, though. I just need to know how to tell the column to use a custom function for displaying the filter choices and applying them. I did find this page: https://www.syncfusion.com/aspnet-core-ui-controls/grid/filtering It has a section which says: "Filter UI and logic for a column is applied based on the column type. It is also possible for the users to define their own custom filter UI and filtering logic for a column to suit their application needs." However, when I click the link below it to view the "Custom filter UI documentation", said documentation doesn't say anything at all about customizing the UI or logic.


So how do I customize the filter UI and logic?



RS Rajapandiyan Settu Syncfusion Team March 31, 2022 01:15 PM UTC

Hi Katherine,


Thanks for your update.


Query #1: It would be a nice improvement if Syncfusion components would throw some kind of error in that situation rather than failing silently.


The actionFailure event will be triggered if any exception is thrown while rendering the Grid component. So, you can use this event to get the error details.


actionFailure: https://ej2.syncfusion.com/javascript/documentation/api/grid#actionfailure


Query #2: it's showing the numeric ID rather than the text value.


By using the filter ItemTemplate feature, you can show the customized data in the Excel/Checkbox filter dialog checklist. But this is used for display purposes and the filtering operations are performed based on its dataSource value.


screenshot:


Query #3: it's showing them grouped together rather than separately.


Since we already said that the Grid columns does not support array type column. But for your requirement, we suggested a workaround to store the values in string format and separated them by comma. By default, the Excel filter dialog shows the value as like in the dataSource. we cannot show them as separate values as per your requirement. It is not feasible in the EJ2 Grid.


Query #4: However, when I click the link below it to view the "Custom filter UI documentation", said documentation doesn't say anything at all about customizing the UI or logic.


By using filterBarTemplate feature, you can render custom component on Filter Bar to filter the records.


FilterBarTemplate: https://ej2.syncfusion.com/aspnetcore/documentation/grid/filtering/filter-bar#filter-bar-template-with-custom-component


Regards,

Rajapandiyan S



KV Katherine Valentine March 31, 2022 04:33 PM UTC

Rajapandiyan,


Thanks for the info. I have a couple requests for clarification.


Where is the documentation for the ItemTemplate for filters? I don't see any mention of it, and you didn't include a link for it. Could I possibly use that to split out a comma delimited string into multiple options in the dropdown? Can I indicate what value to use to filter when an option is picked? If both of those things are true, I think I could get it to work.


If that isn't possible with the ItemTemplate, then it sounds like my only option is to use the filter bar instead. Is there some way to have most of the columns use the Excel style and only customize the columns I need to, or will I have to recreate the Excel style filters from scratch for all columns?



RS Rajapandiyan Settu Syncfusion Team April 1, 2022 10:34 AM UTC

Hi Katherine,


Thanks for your update.


Query #1: Where is the documentation for the ItemTemplate for filters? I don't see any mention of it, and you didn't include a link for it. 


As per your requirement, we have prepared a simple sample with this. By using the filter ItemTemplate feature, you can show the customized data in the Excel/Checkbox filter dialog checklist. But this is used for display purposes and the filtering operations are performed based on its dataSource value.

Find the below code example and sample for more information.


 

[index.cshtml]

            <e-grid-column headerText="Order Details" columns="@( new List<Syncfusion.EJ2.Grids.GridColumn>() { new Syncfusion.EJ2.Grids.GridColumn{

                            Field="ID",

                            HeaderText="ID",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit= new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            Filter= new { itemTemplate="#itemTemplate" },

                            Width="220",

                        }})">

            </e-grid-column>

 

<script id="itemTemplate" type="text/x-template">

    <div> ${customHelper(data)} </div>

</script>

 

<script>

 

    var dummyData = [

        {ItemKey: 1, ItemValue: "Denmark"},

        {ItemKey: 2, ItemValue: "Brazil"},

        {ItemKey: 3, ItemValue: "Germany"},

        {ItemKey: 4, ItemValue: "Austria"},

        {ItemKey: 5, ItemValue: "Switzerland"},

    ]

    function customHelper(data){

        var cellValue = data["ID"].split(","); // get the cell value

        var TextValue = "";

       // do your operation here

        cellValue.map( x => {

            var y = new ej.data.DataManager(dummyData).executeLocal(new ej.data.Query().where("ItemKey","equal", parseInt(x)));

            if(y.length > 0){

                TextValue += y[0].ItemValue + ", ";

            }

        });

        return TextValue;  // return the customized value

    }

</script>


screenshot:


Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/core_3_grid_itemtemplate1149773585.zip


Query #2: If that isn't possible with the ItemTemplate, then it sounds like my only option is to use the filter bar instead. Is there some way to have most of the columns use the Excel style and only customize the columns I need to,

By using column.filter.type property, we can show different filters on a particular column in the Grid. Also, you can use filterTemplate feature to render a custom component to filter the data.


 

[index.cshtml]

 

            <e-grid-column headerText="Order Details" columns="@( new List<Syncfusion.EJ2.Grids.GridColumn>() { new Syncfusion.EJ2.Grids.GridColumn{

                            Field="ID",

                            HeaderText="ID",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit= new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            Filter= new {

                                type="Menu",   // use different filter

                                ui = new {create = "IDFilterCreate", write = "IDFilterwrite", read = "IDFilterread" }  // render custom component for filter

                            },

                            Width="220",

                        }})">

            </e-grid-column>

 

<script>

 

    var dropInstance;

 

    function IDFilterCreate(args){

        var gridObj = document.getElementById("Grid").ej2_instances[0];

        var data = gridObj.dataSource;

        var flValInput = new ej.base.createElement('input', { className: 'flm-input' });

        args.target.appendChild(flValInput);                          

        // create dropdown component

        dropInstance = new ej.dropdowns.DropDownList({

            dataSource: new ej.data.DataManager(data),

            fields: { text: 'ID', value: 'ID' },

            placeholder: 'Select a value',

            popupHeight: '200px'

        });

        dropInstance.appendTo(flValInput);

    }

    function IDFilterwrite(args){ 

        dropInstance.value = args.filteredValue; // bind the filter value

    }

    function IDFilterread(args) {

        args.fltrObj.filterByColumn(args.column.field, "equal", dropInstance.value); // filter the column

    }

</script>

 


Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/core_3_grid_filtermenu_template1744695821.zip


Please get back to us if you need further assistance with this.


Regards,

Rajapandiyan S



KV Katherine Valentine April 1, 2022 03:32 PM UTC

Rajapandiyan,


Excellent! This looks like it'll solve my issue, thank you! I'll let you know if I run into any issues.



RS Rajapandiyan Settu Syncfusion Team April 4, 2022 12:14 PM UTC

Hi Katherine,


Thanks for your update. We will wait to hear from you.


Regards,

Rajapandiyan S



KV Katherine Valentine replied to Rajapandiyan Settu April 5, 2022 07:01 PM UTC

Rajapandiyan,


Unfortunately, the suggested solution doesn't seem to work. My field definition is now this:


new Syncfusion.EJ2.Grids.GridColumn{

                            Field="TradeIds",

                            HeaderText="TRADE",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit=new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            ValueAccessor="tradeFormatter",

                            Filter = new

                            {

                                type ="Menu",

                                ui = new {create = "tradeFilterCreate", write = "tradeFilterWrite", read = "tradeFilterRead"}

                            },

                            Width="200",

                        },


I also changed the underlying data to be a string rather than an array of strings, and the multi-select and editing still all works fine. However, the JS functions defined above never get called. I defined them like this, just to test if they were running, and the breakpoint is never hit and the console.log() statement is never called:


        function tradeFilterCreate(args) {

            console.log(args);

        }


        function tradeFilterRead(args) {

            console.log(args);

        }


        function tradeFilterWrite(args) {

            console.log(args);

        }


Instead of running my functions, I simply get this error when clicking on the filter icon:

Uncaught TypeError: Cannot read properties of undefined (reading '0')

    at e.dropSelectedVal (ej2.min.js:10:8490247)

    at e.renderOperatorUI (ej2.min.js:10:8489057)

    at e.renderOperatorUI (ej2.min.js:10:8502763)

    at e.renderFilterUI (ej2.min.js:10:8502651)

    at e.dialogCreated (ej2.min.js:10:8501969)

    at e.notify (ej2.min.js:10:737776)

    at t.e.trigger (ej2.min.js:10:766841)

    at t.appendTo (ej2.min.js:10:778434)

    at e.renderDlgContent (ej2.min.js:10:8501564)

    at e.openDialog (ej2.min.js:10:8499432)


After I click the column with the custom filter, I get the same error when clicking the filter icon on any other column as well. The other columns still work before I click the custom filter.


I also tried removing this code on my grid: 

<e-grid-filterSettings columns="filterColumns" type="Excel"></e-grid-filterSettings>


However, that didn't cause any difference in how the custom filter behaved (i.e. it didn't do anything but throw an error).


Any thoughts on what the problem is?



RS Rajapandiyan Settu Syncfusion Team April 6, 2022 02:08 PM UTC

Hi Katherine,


Thanks for your update.


By analyzing the error details, we suspect that the type is not set to that column in Grid. We suggest you to set the column type as string to resolve this and maintain string values in the dataSource.


 

            <e-grid-column headerText="Order Details" columns="@( new List<Syncfusion.EJ2.Grids.GridColumn>() { new Syncfusion.EJ2.Grids.GridColumn{

                            Field="ID",

                            HeaderText="ID",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Type = "string",

                            Edit= new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            Filter= new {

                                type="Menu",

                                ui = new {create = "IDFilterCreate", write = "IDFilterwrite", read = "IDFilterread" }

                            },

                            Width="220",

                        }})">

            </e-grid-column>

 


Note: By default, the column type is set based on the first cell value’s data-type in the dataSource. If the first cell value is empty/null, then the column type set as null. In that case, you need to manually set column type. This is the behavior of EJ2 Grid column.


Please let us know if you have any concerns.


Regards,

Rajapandiyan S



KV Katherine Valentine April 6, 2022 10:53 PM UTC

Rajapandiyan,


You were exactly right, that was the issue. I have the filters mostly working how I want now, with one small issue remaining: when a filter is added to another column, I want to reduce the filter options for this column to only what's still showing (just like the Excel type filters do). Let's say I have this grid of data:

CountryCity
USALos Angeles
MexicoMexico City

If the country column is filtered to just "USA", then the visible grid will look like this:

Country (filter = "USA")City
USALos Angeles


In this case, I want the only filter option in the City column to be "Los Angeles". It doesn't make sense to show "Mexico City", because then they could select just that, and no rows at all will show. 

I almost have this working, except I was using grid.currentViewData and realized it will not work correctly if there's a filter on City already. Say the city is filtered to Los Angeles, but the country column has no filters on it. The grid still looks like this:

CountryCity (filter = "Los Angeles")
USALos Angeles


In this case, I want "Mexico City" to still show up as an option. However, if I pull the values from currentViewData, "Mexico City" will be missed, because it's filtered out.


So my question is this: How do I get a filtered set of the data minus the filter on a given column? Is there some easy way? Or maybe there is some way to get the list of values the filter would be using if I weren't customizing it? Either would work. Obviously it must be possible, since the native Excel type filters do it perfectly.


Thanks for all your help!



RS Rajapandiyan Settu Syncfusion Team April 7, 2022 02:31 PM UTC

Hi Katherine,


Thanks for your update.


Before proceeding with your query, kindly share the below details to proceed further.


  1. Are facing the issue with filterTemplate column or Excel type filter column?
  2. Are you want to show the values in dropdown (used as filterTemplate ) popup based on the other columns’ filtered values (like in excel filter)?
  3. Did you bind Grid dataSource as dropdown dataSource (used as filterTemplate)?
  4. Or, Are you binding custom dataSource for dropdown (used as filterTemplate)? - If so, it is not feasible to shoe the popup values based on other columns' filtered value.
  5. If we misunderstood your requirement, kindly explain it in detail.


Regards,

Rajapandiyan S



KV Katherine Valentine April 7, 2022 04:01 PM UTC

Here's my column definition again (the only thing that's changed is I set the type to "string" as you suggested):

new Syncfusion.EJ2.Grids.GridColumn{

                            Field="TradeIds",

                            HeaderText="TRADE",

                            TextAlign=Syncfusion.EJ2.Grids.TextAlign.Center,

                            Edit=new {create = "tradeCreate", read = "tradeRead", destroy = "tradeDestroy", write = "tradeWrite"},

                            ValueAccessor="tradeFormatter",

                            Filter = new {type = "Menu", ui = new {create = "tradeFilterCreate", write = "tradeFilterWrite", read = "tradeFilterRead"} },

                            Width="200",

                            Type="string"

                        },


And here are my JS functions the filter is using:

        let tradeFilterObj;

        let tradeFilterValue = [];


        function tradeFilterCreate(args) {

            getFilterDatasource(args.column.field, contractors);

            let tradeFilterElem = document.createElement('input');

            args.target.appendChild(tradeFilterElem);

            tradeFilterObj = new ej.dropdowns.ListBox({

                //Need to change this datasource to a filtered version

                dataSource: @Html.Raw(Json.Serialize(Model.Contractors)),

                fields: { text: 'Text', value: 'Value' },

                selectionSettings: { mode: 'Multiple', showCheckbox: true }

            });

            tradeFilterObj.appendTo(tradeFilterElem);

        }


        function tradeFilterRead(args) {

            const idArray = [];

            //Data for column is in the form of ";id1;id2;id3;"

            //Searching for ";id;" finds all records which contain that id without any false positives

            for (const id of tradeFilterObj.value) {

                idArray.push(";" + id + ";");

            }


            //Remove any existing filters

            let gridObj = document.getElementById("DataGrid").ej2_instances[0];

            gridObj.clearFiltering([args.column.field]);

            tradeFilterValue = tradeFilterObj.value;


            //If any filters are chosen, apply them

            if (idArray.length > 0) {

                tradeFilterValue = tradeFilterObj.value;

                args.fltrObj.filterByColumn(args.column.field, "contains", idArray);

            }

        }


        function tradeFilterWrite(args) {

            //Filtered values are manually tracked because args.filteredValue doesn't hold all the current filters

            //It's only checked at all to see if the filter was cleared completely

            return tradeFilterObj.value = args.filteredValue ? tradeFilterValue : [];

        }


And this is my attempt at making a datasource with only the visible values, which does work except for the limitation described in my previous post:

function getFilterDatasource(fieldName, idNameMap) {

            const values = []

            let gridObj = document.getElementById("DataGrid").ej2_instances[0];

            //Loop through every visible row

            for (const row of gridObj.currentViewData) {

                if (row[fieldName]) {

                    //Split delimited string into array for processing

                    let idsAsArray = row[fieldName].substring(1, row[fieldName].length - 1).split(';');

                    for (const value of idsAsArray) {

                        values.push(value);

                    }

                }

            }

            const uniqueValues = [...new Set(values)]; //Set removes duplicates

            const datasource = [];

            //Add name to go with ID

            for (const uniqueValue of uniqueValues) {

                datasource.push({ Text: idNameMap[uniqueValue], Value: uniqueValue });

            }

            return datasource;

        }


Hopefully that will help you to get an idea of what I'm trying to achieve. 



KV Katherine Valentine April 7, 2022 06:28 PM UTC

I attempted to get the rows I need by unfiltering the column, getting the visible rows, then filtering again, but it seems like the grid doesn't re-render until after the function is done being called, so it returns the same data as it would if I hadn't messed with the filters at all. Of course, it wouldn't be an ideal solution even if it did work, because the user would see the grid unfilter and re-filter, but it would at least show the correct options.

What I need is something to replace the bold code below which gives me the rows which would be visible if the indicated column had the filter removed.


        function getFilterDatasource(fieldName, idNameMap) {

            const values = []

            let gridObj = document.getElementById("DataGrid").ej2_instances[0];

            let visibleData = gridObj.currentViewData;

            let currentFilter = getCurrentFilterAsArray(fieldName)


            if (currentFilter) {

                gridObj.clearFiltering([fieldName]);

                visibleData = gridObj.currentViewData;

                gridObj.filterModule.filterByColumn(fieldName, "contains", currentFilter);

            }


            //Loop through every visible row

            for (const row of visibleData) {

                if (row[fieldName]) {

                    //Split delimited string into array for processing

                    let idsAsArray = row[fieldName].substring(1, row[fieldName].length - 1).split(';');

                    for (const value of idsAsArray) {

                        values.push(value);

                    }

                }

            }

            const uniqueValues = [...new Set(values)]; //Set removes duplicates

            const datasource = [];

            //Add name to go with ID

            for (const uniqueValue of uniqueValues) {

                datasource.push({ Text: idNameMap[uniqueValue], Value: uniqueValue });

            }

            return datasource;

        }



RS Rajapandiyan Settu Syncfusion Team April 8, 2022 02:03 PM UTC

Hi Katherine,


Thanks for your update.


By analyzing your query, we suspect that you want to show the dropdown (used as filterTemplate for the TradeIds column) values based on the other columns' filtered values. If so, we will prepare the sample for this and will update the further details on Apr 12th, 2022.


We appreciate your patience until then.


Regards,

Rajapandiyan S



KV Katherine Valentine April 8, 2022 06:27 PM UTC

Yes, I want to change which values are shown based on the filters in the other columns. If you call using custom functions to display your own filter a "filterTemplate", then yes, I'm using that.



KV Katherine Valentine April 11, 2022 06:29 PM UTC

Do you need any more info from me to answer this question?



RS Rajapandiyan Settu Syncfusion Team April 12, 2022 12:57 PM UTC

Hi Katherine,


Thanks for your patience.


Query: to show the dropdown (used as filterTemplate for the TradeIds column) values based on the other columns filtered value.


Based on your requirement, you want to show the dropdown values based on other columns’ filtered value. You can achieve this by binding other columns' filter queries to the dropdown component. Find the below code example and sample for more information.


 

[index.cshtml]

 

<script>

    var dropInstance;

 

    function IDFilterCreate(args){

        var gridObj = document.getElementById("Grid").ej2_instances[0];

        var data = gridObj.dataSource;

        var flValInput = new ej.base.createElement('input', { className: 'flm-input' });

        args.target.appendChild(flValInput);   

        var dropdownquery = getDropdownQuery();  // get the other columns’ filter query

                           

        dropInstance = new ej.dropdowns.DropDownList({

            dataSource: new ej.data.DataManager(data),

            fields: { text: 'ID', value: 'ID' },

            placeholder: 'Select a value',

            query: dropdownquery, // bind the other columns’ filter query

            popupHeight: '200px'

        });

        dropInstance.appendTo(flValInput);

    }

 

    function getDropdownQuery(args){

        var grid = document.getElementById("Grid").ej2_instances[0];

        var query = new ej.data.Query();

        var filteredColumns = grid.filterSettings.columns;

        if (filteredColumns.length) {

            var cols = [];

            for (var i = 0; i < filteredColumns.length; i++) {

                var filterColumn = filteredColumns[i];

                if (filterColumn.field != 'ID') {

                    cols.push(filterColumn); // get the filter column details except ID column

                }

            }

            var predicate;

            predicate = getPredicateFromCols(cols); // get predicates for the filtered column

            if (predicate) {

               query.where(predicate); // generate the query based on the filtered values

            }

 

        }

        return query; // return the query

    }

 

    function getPredicateFromCols (columns) {

        var grid = document.getElementById("Grid").ej2_instances[0];

        var predicates = ej.grids.CheckBoxFilterBase.getPredicate(columns);

        var predicateList = [];

        var fPredicate = {};

        var isGrid = grid.getForeignKeyColumns !== undefined;

        var foreignColumn = isGrid ? grid.getForeignKeyColumns() : [];

        for (var _i = 0, _a = Object.keys(predicates); _i < _a.length; _i++) {

            var prop = _a[_i];

            var col = void 0;

            if (col) {

                if (fPredicate.predicate.predicates.length) {

                    predicateList.push(ej.data.Predicate.or(fPredicate.predicate.predicates));

                }

            }

            else {

                predicateList.push(predicates[prop]);

            }

        }

        return predicateList.length && ej.data.Predicate.and(predicateList);

    }

</script>

 


Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/core_3_filtertemp_basedonfiltervalue2134253594.zip


Please get back to us if you need further assistance with this.


Regards,

Rajapandiyan S



KV Katherine Valentine April 15, 2022 11:39 PM UTC

Rajapandiyan,


Thanks for your reply. It's not exactly what I asked for, but it did help me get a lot closer to my goal. I have a couple questions to help me over the finish line. First off, the sample had a line of code commented out that isn't commented in your post:




With that line commented, it's actually the equivalent of this, since most of the conditions can never be true:



Is this intentional? It seems to work, even if a filter is on a column which uses a foreign key, but I don't know every scenario I should test for to be certain. I didn't try it uncommented because it looks like it'll throw an error if col is ever truthy, since fPredicate.predicate is undefined.


My next question is regarding this section, specifically the highlighted lines:



My grid uses a DataManager with a URL, so its datasource is not actually the data, it's a DataManager with a URL which provides the data asynchronously. You may think the answer is to simply do this instead:

However I cannot do that, because when a value appears in the grid multiple times, it also appears multiple times in the dropdown list. I also need to do some parsing to split out the values and whatnot, so I need to get the data for the grid, do some work with it, then give it to this control. Luckily I was able to do all of that using a combination of the DataManager and Query objects you showed me, but I had to make all of my functions async. So now my function to create the filter looks something like this (don't worry about what's in getParsedData(), just know that it takes care of applying the filter query and parsing out the data as needed, and it is async):




This works completely perfectly EXCEPT the grid doesn't wait for it to finish! It runs IDFilterwrite() before the dropdown is instantiated, so the value is always blank. I would just set the value in IDFilterCreate(), but alas, the current filter value isn't contained in the args for that function. It is also a bit of a confusing experience for the user, because it pops up as blank for a moment when the filter is first opened:



The way I see it, there are two good routes to fix this. Hopefully at least one of these is easy:

  1. Tell the grid this function is asynchronous so the grid handles it properly
  2. Get ALL of the current local data of the grid (not currentViewData, that won't work) without hitting the server, so I don't need to make any async calls
My preference is #2, since it's better performance and the filter options should be based on the current data in the grid anyway, but amazingly enough I couldn't find any properties or functions on the grid which allow me to do that. Is there some way to do it that you know of? If not, is there a way to accomplish #1?

In case it makes a difference, this is how the DataManager is defined on my grid:



RS Rajapandiyan Settu Syncfusion Team April 18, 2022 03:12 PM UTC

Hi Katherine


Thanks for your update.


We have created a new ticket under your account for the reported query. We suggest you follow up with that ticket for further updates.


Regards, 

Rajapandiyan S 



KV Katherine Valentine April 19, 2022 03:21 PM UTC

I see the ticket, but it doesn't have any response yet. When should I expect one? 



RS Rajapandiyan Settu Syncfusion Team April 20, 2022 01:18 PM UTC

Hi Katherine,


Sorry for the inconvenience caused.


We have posted the response in the ticket. Kindly check it and update your queries in the same ticket for further follow-up.


Regards, 

Rajapandiyan S 


Loader.
Up arrow icon