RefreshDataAsync in Blazor MultiSelect Dropdown Component
4 Nov 202524 minutes to read
Use the RefreshDataAsync method to refresh the remote data source dynamically without changing the configured Query. This method re-requests data from the configured endpoint (URL) and updates the popup list.
In the following example, the initial render loads five items without using Query. The data source is then refreshed to load eight items from the endpoint by calling RefreshDataAsync.
@using Syncfusion.Blazor
@using MultiSelect_RefreshDataAsync.Data
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.DropDowns
<div>
<button @onclick="ClickHandler">Refresh</button>
</div>
<div>
<SfMultiSelect TValue="int?[]" @ref="Ddlinstance" TItem="OrderDetails1" Placeholder="e.g. Australia" AllowFiltering =true
ShowDropDownIcon="true" PopupHeight="800px">
<MultiSelectEvents TValue="int?[]" TItem="OrderDetails1" Filtering="@Filter"></MultiSelectEvents>
<SfDataManager Url="@url" @ref="Datainstance" Adaptor="Adaptors.ODataV4Adaptor" CrossDomain=true></SfDataManager>
<MultiSelectFieldSettings Text="CustomerID" Value="OrderID"></MultiSelectFieldSettings>
</SfMultiSelect>
</div>
@code {
public string url { get; set; } = "https://services.odata.org/V4/Northwind/Northwind.svc/Orders/?$top=5";
DataManager Datainstance { get; set; }
SfMultiSelect<int?[], OrderDetails1> Ddlinstance { get; set; }
async Task ClickHandler()
{
Datainstance.Url = "https://services.odata.org/V4/Northwind/Northwind.svc/Orders/?$top=8";
await Ddlinstance.RefreshDataAsync();
}
async Task Filter(FilteringEventArgs args)
{
args.PreventDefaultAction = true;
Datainstance.Url = "https://services.odata.org/V4/Northwind/Northwind.svc/Orders/?$top=8";
await Ddlinstance.RefreshDataAsync();
}
public class OrderDetails1
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public int? EmployeeID { get; set; }
public double? Freight { get; set; }
public string ShipCity { get; set; }
public bool Verified { get; set; }
public DateTime? OrderDate { get; set; }
public string ShipName { get; set; }
public string ShipCountry { get; set; }
public DateTime? ShippedDate { get; set; }
public string ShipAddress { get; set; }
}
}
NOTE
When using
RefreshDataAsyncwith filtering enabled, prevent the component’s default filtering action in theFilteringevent (set the cancel flag) before invoking the endpoint and callingRefreshDataAsync. This ensures that custom refresh logic runs without conflicting with the built-in behavior.
Web API adaptor
When using WebApiAdaptor, implement a custom controller that handles OData-style query parameters for both initial loads and refresh requests. In this scenario, the endpoint URL is used for both rendering and refreshing the data source.
The following example shows WebApiAdaptor usage with a controller and the RefreshDataAsync method.
@using MultiSelect_RefreshDataAsync.Data
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.DropDowns
<div>
<button @onclick="ClickHandler">Refresh</button>
</div>
<div>
<SfMultiSelect TValue="string" TItem="Order" @ref="Ddlinstance" AllowFiltering=true>
<MultiSelectEvents TValue="string" TItem="Order" Filtering="@Filter" ></MultiSelectEvents>
<SfDataManager Url="@url" Adaptor="Adaptors.WebApiAdaptor" @ref="Datainstance"></SfDataManager>
<MultiSelectFieldSettings Text="CustomerID" Value="OrderID"></MultiSelectFieldSettings>
</SfMultiSelect>
</div>
@code{
public string url { get; set; } = "/api/Default/?$top=8";
DataManager Datainstance { get; set; }
SfMultiSelect<string, Order> Ddlinstance { get; set; }
async Task ClickHandler()
{
Datainstance.Url = "/api/Default/?$top=5";
await Ddlinstance.RefreshDataAsync();
}
async Task Filter(FilteringEventArgs args)
{
args.PreventDefaultAction = true;
Datainstance.Url = "/api/Default/?$top=5";
await Ddlinstance.RefreshDataAsync();
}
}using System;
using System.Linq;
using MultiSelect_RefreshDataAsync.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Syncfusion.Blazor.Data;
using System.Linq.Dynamic.Core;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace MultiSelect_WebAPIMultiSelect_WebAPI.Controller
{
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
public OrderDataAccessLayer OrderService = new OrderDataAccessLayer();
// GET: api/Default
[HttpGet]
public async Task<object> Get(int? code)
{
try
{
Microsoft.AspNetCore.Http.IQueryCollection queryString = Request.Query;
if (queryString == null)
return null;
IQueryable<Order> dataSource = OrderService.GetAllOrders();
int countAll = dataSource.Count();
StringValues sSkip, sTake, sFilter, sSort;
int skip = (queryString.TryGetValue("$skip", out sSkip)) ? Convert.ToInt32(sSkip[0]) : 0;
int top = (queryString.TryGetValue("$top", out sTake)) ? Convert.ToInt32(sTake[0]) : countAll;
string filter = (queryString.TryGetValue("$filter", out sFilter)) ? sFilter[0] : null; //filter query
List<DynamicLinqExpression.Filter> listFilter = ParsingFilterFormula.PrepareFilter(filter);
if (listFilter.Count() > 0)
{
Expression<Func<Order, bool>> deleg = DynamicLinqExpression.ExpressionBuilder.GetExpressionFilter<Order>(listFilter);
dataSource = dataSource.Where(deleg);
}
string sort = (queryString.TryGetValue("$orderby", out sSort)) ? sSort[0] : null; //sort query
if (sort != null)
{
string s = DynamicLinqExpression.GetSortString(sort);
if (s == null)
return null;
else if (s.Length > 0)
{
dataSource = dataSource.OrderBy(s);
}
}
int countFiltered = dataSource.Count();
dataSource = dataSource.Skip(skip).Take(top);
if (queryString.Keys.Contains("$inlinecount"))
return new { Items = dataSource, Count = countFiltered };
else
return dataSource;
}
catch (Exception ex)
{
return null;
}
}
}
//========== parsing the filter formula
class ParsingFilterFormula
{
public static List<DynamicLinqExpression.Filter> PrepareFilter(string filter)
{
/* possible filters from SfGrid:
startswith(tolower(Street),'sa')
endswith(tolower(Zip),'1')
substringof('11',tolower(Zip))
tolower(Zip) eq '0-11'
tolower(Zip) ne '0-11'
Timestamp lt null
lt, le, gt, ge
multiple: (startswith(tolower(Street),'sa')) and (startswith(tolower(Country),'xy'))
*/
const string patt_startswith = "startswith(";
const string patt_endswith = "endswith(";
const string patt_substringof = "substringof(";
const string patt_tolower = "tolower(";
try
{
if (filter == null || filter.Length < 2)
return new List<DynamicLinqExpression.Filter>();
List<DynamicLinqExpression.Filter> listFilter = new List<DynamicLinqExpression.Filter>();
if (filter.Substring(0, 1) == "(" && filter.Substring(filter.Length - 1, 1) == ")")
filter = filter.Substring(1, filter.Length - 2); // remove first and last parentheses
string[] filterparts = filter.Split(") and ("); // get parts for multiple selection
foreach (string filterpart in filterparts)
{
DynamicLinqExpression.Op operation = DynamicLinqExpression.Op.None;
string filterfield = "";
string filtervalue = "";
if (filterpart.Length > 2 && filterpart.Substring(filterpart.Length - 1) == ")" && //startswith(tolower(Street),'sa') or endswith(tolower(Zip),'1')
(filterpart.StartsWith(patt_startswith) || filterpart.StartsWith(patt_endswith)))
{
string s;
DynamicLinqExpression.Op op = DynamicLinqExpression.Op.None;
if (filterpart.StartsWith(patt_startswith))
{
s = filterpart.Substring(patt_startswith.Length);
op = DynamicLinqExpression.Op.StartsWith;
}
else
{
s = filterpart.Substring(patt_endswith.Length);
op = DynamicLinqExpression.Op.EndsWith;
}
// tolower(Street),'sa')
s = s.Substring(0, s.Length - 1);
// tolower(Street),'sa'
string[] p = s.Split(",", 2);
if (p.Length == 2)
{
filterfield = p[0]; // may be "tolower(Street)"
if (filterfield.StartsWith(patt_tolower) && filterfield.Contains(")"))
{
filterfield = filterfield.Split('(', ')')[1];
}
filtervalue = p[1];
if (filtervalue.Length >= 2 && filtervalue[0] == '\'')
{
filtervalue = filtervalue.Substring(1, filtervalue.Length - 2);
}
if (filtervalue.Length > 0 && filterfield.Length > 0)
operation = op;
}
}
else if (filterpart.Length > 2 && filterpart.Substring(filterpart.Length - 1) == ")" && //substringof('11-111',tolower(Zip))
filterpart.StartsWith(patt_substringof))
{
string s = filterpart.Substring(patt_substringof.Length);
// '11-111', tolower(Zip))
s = s.Substring(0, s.Length - 1);
// '11-111', tolower(Zip)
string[] p = s.Split(",", 2);
if (p.Length == 2)
{
filterfield = p[1]; // may be "tolower(Street)"
if (filterfield.StartsWith(patt_tolower) && filterfield.Contains(")"))
{
filterfield = filterfield.Split('(', ')')[1];
}
filtervalue = p[0];
if (filtervalue.Length >= 2 && filtervalue[0] == '\'')
{
filtervalue = filtervalue.Substring(1, filtervalue.Length - 2);
}
if (filtervalue.Length > 0 && filterfield.Length > 0)
operation = DynamicLinqExpression.Op.Contains;
}
}
else if (filterpart.Length > 2) //tolower(Zip) eq '0-11' or Timestamp lt null
{
string s = filterpart;
string[] p;
if (s.StartsWith(patt_tolower) && s.Contains(")")) // tolower(Zip) eq '0-11'
{
s = s.Substring(patt_tolower.Length);
// Zip) eq '0-11'
p = s.Split(")", 2);
}
else // Zip eq '0-11'
{
p = s.Split(" ", 2);
}
if (p.Length == 2)
{
filterfield = p[0];
s = p[1].Trim(); // eq '0-11'
p = s.Split(" ", 2);
if (p.Length == 2)
{
filtervalue = p[1];
if (filtervalue.Length >= 2 && filtervalue[0] == '\'')
{
filtervalue = filtervalue.Substring(1, filtervalue.Length - 2);
}
if (filtervalue.Length > 0 && filterfield.Length > 0)
{
switch (p[0])
{
case "eq":
operation = DynamicLinqExpression.Op.Equals;
break;
case "ne":
operation = DynamicLinqExpression.Op.NotEquals;
break;
case "lt":
operation = DynamicLinqExpression.Op.LessThan;
break;
case "le":
operation = DynamicLinqExpression.Op.LessThanOrEqual;
break;
case "gt":
operation = DynamicLinqExpression.Op.GreaterThan;
break;
case "ge":
operation = DynamicLinqExpression.Op.GreaterThanOrEqual;
break;
}
}
}
}
}
if (operation != DynamicLinqExpression.Op.None)
{
listFilter.Add(new DynamicLinqExpression.Filter { PropertyName = filterfield, Operation = operation, Value = filtervalue.ToString() });
};
}
return listFilter;
}
catch (Exception)
{
return new List<DynamicLinqExpression.Filter>();
}
}
}
class DynamicLinqExpression
{
public static string GetSortString(string sSort)
{
try
{
// "SubStandard,Standard,Class desc" -> "SubStandard ASC, Standard ASC, Class DESC"
string[] listSort = sSort.Split(",");
if (listSort.Length == 0)
return "";
string sOut = "";
foreach (string s in listSort)
{
if (s.Length <= 0)
return null; // error
string[] p = s.Split(" ");
if (p.Length < 1 || p[0].Trim().Length == 0)
return null; // error
bool bDescending = (p.Length > 1 && p[1].Contains("desc"));
string sortColumn = p[0];
if (sOut.Length > 0)
sOut += ", ";
sOut += p[0].Trim();
if (p.Length > 1 && p[1].Contains("desc"))
sOut += " DESC";
else
sOut += " ASC";
}
return sOut;
}
catch (Exception ex)
{
return null;
}
}
//========== Build Where Clause Dynamically in Linq basing on https://www.codeproject.com/Tips/582450/Build-Where-Clause-Dynamically-in-Linq
public enum Op
{
None,
Equals,
NotEquals,
GreaterThan,
LessThan,
GreaterThanOrEqual,
LessThanOrEqual,
Contains,
StartsWith,
EndsWith
}
public class Filter
{
public string PropertyName { get; set; }
public Op Operation { get; set; }
public object Value { get; set; }
}
public static class ExpressionBuilder
{
private static MethodInfo containsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
public static Expression<Func<T, bool>> GetExpressionFilter<T>(IList<Filter> filters)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpressionFilter<T>(param, filters[0]);
else if (filters.Count == 2)
exp = GetExpressionFilter<T>(param, filters[0], filters[1]);
else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
if (exp == null)
exp = GetExpressionFilter<T>(param, filters[0], filters[1]);
else
exp = Expression.AndAlso(exp, GetExpressionFilter<T>(param, filters[0], filters[1]));
filters.Remove(f1);
filters.Remove(f2);
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpressionFilter<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpressionFilter<T>(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
ParameterExpression table = Expression.Parameter(typeof(T), "");
Expression column = Expression.PropertyOrField(table, filter.PropertyName);
ConstantExpression constantExpression;
if (column.Type == typeof(DateTime) || column.Type == typeof(DateTime?))
{
DateTime? d = MyUtils.GetDateFromString(filter.Value.ToString());
constantExpression = Expression.Constant(d);
}
else if (column.Type == typeof(int) || column.Type == typeof(int?))
{
int? i = MyUtils.StringToInt(filter.Value.ToString(), 0);
constantExpression = Expression.Constant(i);
}
else
constantExpression = Expression.Constant(filter.Value);
UnaryExpression unaryExpression = Expression.Convert(constantExpression, column.Type);
switch (filter.Operation)
{
case Op.Equals:
return Expression.Equal(member, unaryExpression);
case Op.NotEquals:
return Expression.NotEqual(member, unaryExpression);
case Op.GreaterThan:
return Expression.GreaterThan(member, unaryExpression);
case Op.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, unaryExpression);
case Op.LessThan:
return Expression.LessThan(member, unaryExpression);
case Op.LessThanOrEqual:
return Expression.LessThanOrEqual(member, unaryExpression);
case Op.Contains:
return Expression.Call(member, containsMethod, unaryExpression);
case Op.StartsWith:
return Expression.Call(member, startsWithMethod, unaryExpression);
case Op.EndsWith:
return Expression.Call(member, endsWithMethod, unaryExpression);
}
return null;
}
private static BinaryExpression GetExpressionFilter<T>(ParameterExpression param, Filter filter1, Filter filter2)
{
Expression bin1 = GetExpressionFilter<T>(param, filter1);
Expression bin2 = GetExpressionFilter<T>(param, filter2);
return Expression.AndAlso(bin1, bin2);
}
}
}
public class MyUtils
{
public static int StringToInt(string sVal, int iDefault)
{
if (sVal == null)
return iDefault;
try
{
return System.Convert.ToInt32(sVal);
}
catch (Exception)
{
return iDefault;
}
}
//convert string to date (string may be: 2000.12.31 or 31.12.2000 or 31.12.00 or 1.1.2001 or 1.1.01 - any delimiter)
//if the string contains of additional time HH:MM then it is also used
public static DateTime? GetDateFromString(string sDateTime)
{
DateTime dtRet = DateTime.Now;
try
{
string s1 = GetDateFromStringPart(ref sDateTime);
string s2 = GetDateFromStringPart(ref sDateTime);
string s3 = GetDateFromStringPart(ref sDateTime);
string s4 = GetDateFromStringPart(ref sDateTime);
string s5 = GetDateFromStringPart(ref sDateTime);
int vD = 0;
int vM = 0;
int vY = 0;
int vHH = 0;
int vMM = 0;
if (s1.Length != 1 && s1.Length != 2 && s1.Length != 4 ||
s2.Length != 1 && s2.Length != 2 ||
s3.Length != 2 && s3.Length != 4 ||
s1.Length == 4 && s3.Length == 4)
return null;
if (s1.Length == 4)
{
// YYYY.MM.DD
vY = StringToInt(s1, -1);
vM = StringToInt(s2, -1);
vD = StringToInt(s3, -1);
}
else
{
// DD.MM.YYYY or DD.MM.YY
vD = StringToInt(s1, -1);
vM = StringToInt(s2, -1);
vY = StringToInt(s3, -1);
if (vY < 90)
vY += 2000;
else if (vY < 100)
vY += 1900;
}
if (vD < 1 || vD > 31 || vM < 1 || vM > 12 || vY < 1990 || vY > 2090)
return null;
if (s4.Length > 0 && s5.Length > 0)
{
vHH = StringToInt(s4, -1);
vMM = StringToInt(s5, -1);
if (vHH < 0 || vHH > 23 || vMM < 0 || vMM > 59)
return null;
}
else
{
vHH = 0;
vMM = 0;
}
dtRet = new DateTime(vY, vM, vD, vHH, vMM, 0);
return dtRet;
}
catch (Exception ex)
{
return null;
}
}
private static string GetDateFromStringPart(ref string s)
{
string sPart = "";
while (!string.IsNullOrEmpty(s) && (s[0] < '0' || s[0] > '9'))
{
s = s.Substring(1);
}
while (!string.IsNullOrEmpty(s) && s[0] >= '0' && s[0] <= '9')
{
sPart += s[0];
s = s.Substring(1);
}
return sPart;
}
}
}URL adaptor
When using UrlAdaptor, the initial load requires Query.RequiresCount() to render data from the endpoint. For subsequent refreshes with RefreshDataAsync, the query is not required; only the endpoint URL is needed.
The following example shows UrlAdaptor usage with a controller and the RefreshDataAsync method.
@using MultiSelect_RefreshDataAsync.Data
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.DropDowns
<div>
<button @onclick="ClickHandler">Refresh</button>
</div>
<div>
<SfMultiSelect TValue="string" TItem="EmployeeData" @ref="Ddlinstance" @bind-Value="AutoVal" AllowFiltering=true Placeholder="Select a Employee" Query="RemoteDataUnidad">
<SfDataManager Url="@url" Adaptor="Adaptors.UrlAdaptor" @ref="Datainstance" CrossDomain="true"></SfDataManager>
<MultiSelectFieldSettings Value="Title" />
<MultiSelectEvents TValue="string" TItem="EmployeeData" Filtering="@Filter" />
</SfMultiSelect>
</div>
@code{
public string AutoVal { get; set; }
public string url { get; set; } = "/api/Values/3";
DataManager Datainstance { get; set; }
SfMultiSelect<string, EmployeeData> Ddlinstance { get; set; }
async Task ClickHandler()
{
Datainstance.Url = "/api/Values/5";
await Ddlinstance.RefreshDataAsync();
}
async Task Filter(FilteringEventArgs args)
{
args.PreventDefaultAction = true;
Datainstance.Url = "/api/Values/5";
await Ddlinstance.RefreshDataAsync();
}
public class EmployeeData
{
public int? Id { get; set; }
public EmployeeName Name { get; set; }
public string Title { get; set; }
}
public class EmployeeName
{
public int FirstName { get; set; }
public Emp LastName { get; set; }
public string Text { get; set; }
}
public static List<EmployeeData> order = new List<EmployeeData>();
public Query RemoteDataUnidad = new Query().RequiresCount();
}using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Syncfusion.Blazor;
using MultiSelect_RefreshDataAsync.Data;
namespace MultiSelect_RefreshDataAsync.Controller
{
[Route("api/[controller]/{top}")]
[ApiController]
public class ValuesController : ControllerBase
{
public ValuesController()
{
BindDataSource();
}
public static List<EmployeeData> order = new List<EmployeeData>();
[HttpPost]
public object Post([FromBody] DataManagerRequest dm, int top)
{
if (order.Count == 0)
{
BindDataSource();
}
IEnumerable DataSource = order.ToList();
if (dm.Search != null && dm.Search.Count > 0)
{
DataSource = DataOperations.PerformSearching(DataSource, dm.Search); //Search
}
if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting
{
DataSource = DataOperations.PerformSorting(DataSource, dm.Sorted);
}
if (dm.Where != null && dm.Where.Count > 0) //Filtering
{
DataSource = DataOperations.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
}
int count = DataSource.Cast<EmployeeData>().Count();
if (dm.Skip != 0)
{
DataSource = DataOperations.PerformSkip(DataSource, dm.Skip); //Paging
}
if (dm.Take != 0)
{
DataSource = DataOperations.PerformTake(DataSource, dm.Take);
}
if (top !=0)
{
DataSource = DataOperations.PerformTake(DataSource, top);
}
return new { result = DataSource, count = count };
}
private void BindDataSource()
{
if (order.Count == 0)
{
order = Enumerable.Range(1, 9).Select(x => new EmployeeData()
{
Id = x,
Name = new EmployeeName()
{
FirstName = x,
Text = (new string[] { "ALFKI", "VINET", "BLONP", "BOLID", "WELLI" })[new Random().Next(5)],
},
Title = (new string[] { "Sales Representative", "Vice President, Sales", "Sales Manager",
"Inside Sales Coordinator","Sales Representative", "Vice President, Sales", "Sales Manager",
"Inside Sales Coordinator","Sales Representative", "Vice President, Sales", "Sales Manager",
"Inside Sales Coordinator","Sales Representative", "Vice President, Sales", "Sales Manager",
"Inside Sales Coordinator" })[new Random().Next(7)],
}).ToList();
}
}
}
}