SfDropDownList with CustomAdaptor and a Query with AddParams throws exception

Hi,

I'm observing an exception thrown when I use SfDropDownList configured with a custom adaptor and a query that has a parameter specified using AddParams. This only appears to happen in release mode -- debug mode works correctly. If I don't add a parameter to the query, everything works correctly.

The custom adapter in my implementation has a rather large data set, so only a small subset will be available to the adapter if it does a read. The user can access the other data by allowing filtering on the component so that when the user types, the items populate with matching values (which works fine). I've observed that on initial read, if the currently bound item of the dropdown box is not in the returned subset of data from the custom adaptor, the dropdown box will appear to not have a selected value (third dropdown box in the following example). However that initial query does not indicate the selected item, therefore the adaptor does not know it needs to include that value in the subset it returns. I figured this could be remedied by making sure the 'key' parameter in the query was set to the selected item ID , but I was unable to figure out how to make that work -- the key parameter in the Read/ReadAsync method in the adaptor is always null. Passing anything in the query using the AddParams method works in Debug mode but fails in Release mode with a ArgumentNullException (details below). 

Is there something I should be doing to initialize the initial value of the dropdown correctly (basically ensure the initial selected value is returned from the data source on its first read while limiting a large data set to a few values)?


I'm using Syncfusion.Blazor 18.4.0.35 with Chrome 87.0.4280.141 (Official Build) (64-bit)

In case you are unable to reproduce the problem here's a simplifed example that seems to produce the result.

@*Throws exception*@

<SfDropDownList TValue="string" TItem="CustomItem" Placeholder="Select Custom Item" Query="@(new Query().AddParams("some", "param"))" AllowFiltering="true" @bind-Value="@(SelecteItem2.Id)" FloatLabelType="FloatLabelType.Always">

    <SfDataManager Adaptor="Adaptors.CustomAdaptor" AdaptorInstance="@typeof(CustomAdaptor)">SfDataManager>

    <DropDownListFieldSettings Text="Name" Value="Id">DropDownListFieldSettings>

SfDropDownList>

<SfDropDownList TValue="string" TItem="CustomItem" Placeholder="Select Custom Item" AllowFiltering="true" @bind-Value="@(SelecteItem2.Id)" FloatLabelType="FloatLabelType.Always">

    <SfDataManager Adaptor="Adaptors.CustomAdaptor" AdaptorInstance="@typeof(CustomAdaptor)">SfDataManager>

    <DropDownListFieldSettings Text="Name" Value="Id">DropDownListFieldSettings>

SfDropDownList>

@*Does not initialize to the selected value because the datasource limits output to 5 but how do I let the adaptor know I need the selected value in the list of items on initial read?*@

<SfDropDownList TValue="string" TItem="CustomItem" Placeholder="Select Custom Item" AllowFiltering="true" @bind-Value="@(SelecteItem7.Id)" FloatLabelType="FloatLabelType.Always">

    <SfDataManager Adaptor="Adaptors.CustomAdaptor" AdaptorInstance="@typeof(CustomAdaptor)">SfDataManager>

    <DropDownListFieldSettings Text="Name" Value="Id">DropDownListFieldSettings>

SfDropDownList>

@code {

    CustomItem SelecteItem2 = new CustomItem { Id = "2", Name = "2 Default" };

    CustomItem SelecteItem7 = new CustomItem { Id = "7", Name = "7 Default"};

    public class CustomItem

    {

        public string Id { get; set; }

        public string Name { get; set; }

    }

 

    public class CustomAdaptor : DataAdaptor

    {

        CustomItem[] Items = new CustomItem[]

        {

                new CustomItem { Id = "1", Name = "Item 1" },

                new CustomItem { Id = "2", Name = "Item 2" },

                new CustomItem { Id = "3", Name = "Item 3" },

                new CustomItem { Id = "4", Name = "Item 4" },

                new CustomItem { Id = "5", Name = "Item 5" },

                new CustomItem { Id = "6", Name = "Item 6" },

                new CustomItem { Id = "7", Name = "Item 7" }

        };

        public override object Read(DataManagerRequest dataManagerRequest, string key = null)

        {

            try

            {

 

                var req = (dataManagerRequest == null) ? "null" : Newtonsoft.Json.JsonConvert.SerializeObject(dataManagerRequest);

                System.Diagnostics.Debug.WriteLine("Reading custom adaptor. Key is " + key + ", req: " + req);

                int count = 5;

                if (dataManagerRequest.Take > 0) count = Math.Min(5, dataManagerRequest.Take); //Simulate data limit

                var items = Items.Take(count);

                var value = dataManagerRequest?.Where?.FirstOrDefault()?.value?.ToString();

                if (value != null) items = items.Where(i => i.Name.StartsWith(value));

                if (dataManagerRequest.RequiresCounts) return new DataResult() { Result = items, Count = Items.Count() };

                else return items;

            }

            catch(Exception e)

            {

                System.Diagnostics.Debug.WriteLine("Exception: " + e.GetExceptionDetail());

                return null;

            }

        }

        public override async Task<object> InsertAsync(DataManager dataManager, object value, string key)

        {

            return value;

        }

        public override async Task<object> RemoveAsync(DataManager dataManager, object value, string keyField, string key)

        {

            return value;

        }

        public override async Task<object> UpdateAsync(DataManager dataManager, object value, string keyField, string key)

        {

            return value;

        }

    }

}

 

The exception:

Uncaught (in promise) Error: System.ArgumentNullException: Value cannot be null.

Parameter name: source
  at System.Linq.Enumerable.Cast[TResult] (System.Collections.IEnumerable source) <0x7911db8 + 0x0002a> in :0 
  at Syncfusion.Blazor.Data.BlazorAdaptor.ProcessResponse[T] (System.Object Data, Syncfusion.Blazor.DataManagerRequest queries) <0x7911710 + 0x002f6> in ...


3 Replies 1 reply marked as answer

BC Berly Christopher Syncfusion Team January 29, 2021 11:32 AM UTC

Hi Colin, 
  
Greetings from Syncfusion support. 
  
Query 1: 
  
@*Throws exception*@ 
  
Response: 
  
While running the sample with shared code snippet, we did not receive any exception both in the release and debug mode in DropDownList component. So, we have prepared the sample and attached it below, 
  
  
So, please check the sample and share any issue reproducing case that will help us to investigate further from our end.  
  
Query 2: 
  
@*Does not initialize to the selected value because the datasource limits output to 5 but how do I let the adaptor know I need the selected value in the list of items on initial read?*@ 
  
Response: 
  
We have checked the provided code snippet. You have used the custom adaptor and returned the 5 items with help of take query for the DropDownList component data source in the Read method. If you assigned the value beyond this item, then it will not be displayed in the component since bind-value will be shown based on the returned item list alone.  
  
If you want to display the beyond item in the DropDownList component means, we need to return the required data for the data source.  
  
Regards, 
Berly B.C 


Marked as answer

CO Colin OBrien January 29, 2021 05:11 PM UTC

Thanks Berly,

The AddParams exception has stopped occuring last night. It stopped after upgrading some of the dotnet libraries but I don't know the cause for sure at this point, but its likely something on my side.

Per the last issue, where the dropdown does a read on the adaptor with a selected item, it works if I use my own query but I would suggest a change. I propose the dropdown should pass something to the adaptor read method expressing the selected item it needs. Perhaps this is a stand alone query for the item or its passed in every read. The supporting argument for this being that in large data sets where it is not practical to return the entire set, making sure the selected value is in the set is not possible since the default query is always empty. The dropdown is requiring the item in the dataset yet not letting the adaptor know it needs it, and from the point of view of the developer its a bit counter intuitive. The workaround is to use the AddParams query method but it seems like the selected value should be passed to the adaptor by default in the query or some other parameter. I see there's  a 'key' parameter but I'm not sure how or what that is used for but I was unable to get that working in the past.

Thanks for your help on this,

Colin


BC Berly Christopher Syncfusion Team February 1, 2021 02:10 PM UTC

Hi Colin, 
  
If you want to send additional parameter to the server then we can use AddParams method. Else, if you are typing any character that value will be automatically received in the where query of the  data manager instance in the read method without using add param method. Please find the screenshot below. 
  
 
  
If we misunderstood your query, please share the issue details with any screenshot or video demonstration that will help us to check and proceed further at our end. 
  
Regards, 
Berly B.C 


Loader.
Up arrow icon