[Solved] dynamic control : kendo multi select filter not working

1 Answer 9 Views
MultiSelect
Saranya
Top achievements
Rank 1
Iron
Saranya asked on 18 Jun 2026, 08:52 AM | edited on 18 Jun 2026, 08:54 AM

   public static MultiSelectBuilder CreateMultiSelect<T>(IHtmlHelper<T> Html, ScreenControlViewModel m)
   {
       var ctrl = Html.Kendo()
           .MultiSelect()
           .Name(m.ControlName)
           .Placeholder(m.PlaceholderText)
           .DataTextField(m.SelectedItemDisplayField)
           .DataValueField(m.ValueFieldName)
           .Filter(FilterType.Contains)
  
//.AutoBind(!string.IsNullOrEmpty(m.Value + "") ? true : false)
//.AutoBind(false)
// .HtmlAttributes(new { style = "width: 100%;" })
.DataSource(source =>
           {
               source.Read(read =>
               {
                   read.Action(m.DataReadActionName, m.DataReadControllerName, m.RouteValues).Data(m.DataReadScriptFunctionName + "('" + m.ControlName + "')");
               })
               .ServerFiltering(true);
           });

       if (m.Value != null)
       {
           if (m.Value is IEnumerable)
               ctrl.Value(m.Value as IEnumerable);

           if (m.Value is string)
               ctrl.Value(m.Value + "");
       }

       if (m.readOnly)
           ctrl.HtmlAttributes(new { style = "width: 100%;", @readonly = "readonly" });
       else
           ctrl.HtmlAttributes(new { style = "width: 100%;" });

       if (!string.IsNullOrWhiteSpace(m.ChangeScriptFunctionName))
           ctrl.Events(e => e.Change(m.ChangeScriptFunctionName));

       if (!string.IsNullOrWhiteSpace(m.SelectScriptFunctionName))
           ctrl.Events(e => e.Select(m.SelectScriptFunctionName));

       return ctrl;
   }

 public ActionResult GetDynamicControlDataForMCombobox(int screenControlQueryID, string text)

{

 try
 {
     base.TraceLog("DataService GetDynamicControlDataForMCombobox", $"{SessionUser.Current.Username} -GetDynamicControlDataForMCombobox request");
     //using (var db = AMS.CreateNewEntityObject())
     {
         ASelectionControlQueryTable tbl = ASelectionControlQueryTable.GetItem(_db, screenControlQueryID);

         //add the where condition for the query
         string whereCondition = "";
         string OrderByQuery = "";
         string[] filterFields = tbl.SearchFields.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         if (string.Compare(text, "Select Employee") == 0)
         {
             text = "";
         }
         Dictionary<string, object> parameters = new Dictionary<string, object>();
         if ((!string.IsNullOrEmpty(text)) && (filterFields.Length > 0))
         {
             foreach (var f in filterFields)
             {
                 var field = f.Trim();
                 if (whereCondition.Length > 0)
                     whereCondition += " OR ";

                 whereCondition += $"{field} like @{field}";
                 parameters.Add($"@{field}", $"%{text}%");
             }
         }

         if (whereCondition.Length > 0)
             whereCondition = " WHERE " + whereCondition;
         if (!string.IsNullOrEmpty(tbl.OrderByQuery))
             OrderByQuery = "" + tbl.OrderByQuery;

         string finalQuery = $"SELECT TOP {maxRecordsPerRequest} * FROM ({tbl.Query}) A {whereCondition} {OrderByQuery}";

  System.Data.DataTable dt = PMMSContext.GetDataTable(finalQuery, parameters, false);

  return Json(dt);

}

  public static DataTable GetDataTable(string procedureName, Dictionary<string, object> parameters, bool isProcedure = true)
  {
      using (SqlConnection cn = GetSqlConnection())
      {
          var cmd = cn.CreateCommand();
          cmd.CommandText = procedureName;
          if (isProcedure)
          {
              cmd.CommandType = CommandType.StoredProcedure;
          }
          else
          {
              cmd.CommandType = CommandType.Text;
          }

          cmd.CommandTimeout = CommandTimeout;
          if (parameters != null)
          {
              foreach (string key in parameters.Keys)
              {
                  if (key.StartsWith("@"))
                      cmd.Parameters.AddWithValue(key, parameters[key]);
                  else
                      cmd.Parameters.AddWithValue("@" + key, parameters[key]);
              }
          }

          //if(procedureName.Contains("@WarehouseID"))
          //{
          //    cmd.Parameters.AddWithValue("@WarehouseID" , SessionUserHelper.CurrentSessionUser.WarehouseID.ToString());
          //}

          SqlDataAdapter da = new SqlDataAdapter(cmd);
          var ds = new DataTable();
          da.Fill(ds);

          return ds;
      }
  }

queries I am maintaining in backend . withoot linq query and load the data like that . when filter the details not filter working . if am used the json method its working filters. if am used datatable return values not working filter.

1 Answer, 1 is accepted

Sort by
0
Rumen
Telerik team
answered on 23 Jun 2026, 07:55 AM

Hi Saranya,

Thank you for sharing the details. Based on your code and description, there are a few issues causing the MultiSelect filter not to work when returning a DataTable from the backend. Below you will find the root causes and recommended fixes.

Problem 1: DataTable Does Not Serialize Correctly with System.Text.Json

ASP.NET Core's default JSON serializer (System.Text.Json) does not support DataTable serialization. When you return Json(dt), the response is either empty or malformed, so the MultiSelect receives no data and filtering appears broken. A List<T> or anonymous objects serialize correctly, which is why that path works.

Fix — convert DataTable to a list of dictionaries before returning:


var result = dt.AsEnumerable()
    .Select(row => dt.Columns.Cast<DataColumn>()
        .ToDictionary(
            col => col.ColumnName,
            col => row[col] == DBNull.Value ? null : row[col]))
    .ToList();

return Json(result);
Problem 2: Server Filtering Parameter Mismatch
With ServerFiltering(true), the Kendo MultiSelect sends the typed text as filter[filters][0][value], not as text. Your action method signature GetDynamicControlDataForMCombobox(int screenControlQueryID, string text) won't bind the filter value automatically.

Fix — update your JavaScript .Data() function to extract the filter value and pass it as text:
function yourDataFunction(controlName) {
    var widget = $("#" + controlName).data("kendoMultiSelect");
    return {
        text: widget ? widget.input.val() : ""
    };
}

This ensures the typed search term is sent as the text parameter your action already expects.

Additional Suggestions

1. SQL Injection Risk in Column Name Concatenation

Your SearchFields column names are concatenated directly into the SQL string:

whereCondition += $"{field} like @{field}";

While the values are parameterized, the column names from tbl.SearchFields are not validated. If SearchFields can be modified by a user or comes from untrusted input, this is a SQL injection vector. Whitelist allowed column names or validate them against the actual table schema before use.

2. Verify the Response Shape in the Browser

Before changing C# code, open DevTools → Network and inspect the actual JSON returned from your action. Confirm:

  • The response is a flat array ([{...}, {...}]), not a nested object like { "rows": [...] } that DataTable sometimes produces.
  • The column name casing (e.g., EmployeeID vs employeeId) exactly matches m.ValueFieldName and m.SelectedItemDisplayField — these are case-sensitive in the widget.

3. AutoBind Interaction with Pre-selected Values

The commented-out .AutoBind(false) combined with .Value(...) can cause issues: with AutoBind(false), the widget won't fetch display text for pre-set values on load unless you also provide the full value objects via .BindTo(...). If pre-selected items show as blank, re-enable AutoBind(true) (the default) or populate via BindTo.

4. Hardcoded Placeholder Text Comparison

This comparison in your backend is fragile:

if (string.Compare(text, "Select Employee") == 0)
    text = "";

Use StringComparison.OrdinalIgnoreCase and consider moving this logic to the client — don't send placeholder text as a filter value at all.

Summary

IssueCauseFix
Filter data not loadingDataTableJson() fails with System.Text.JsonConvert to List<Dictionary<string, object>> before return Json(...)
Filter term not sentServerFiltering sends filter[filters][0][value], not textExtract value in .Data() JS function and map it to text
SQL injection riskColumn names from SearchFields concatenated into SQLWhitelist or validate column names before use
Pre-selected values blankAutoBind(false) skips display text fetchUse AutoBind(true) or provide data via BindTo
Placeholder text sent as filterHardcoded case-sensitive string check on backendHandle on client; use OrdinalIgnoreCase if kept on server

Regards,
Rumen
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
MultiSelect
Asked by
Saranya
Top achievements
Rank 1
Iron
Answers by
Rumen
Telerik team
Share this question
or