How to hande casading dropdons with odata v4 wep api

Hello Team,

I am using Syncfusion.Blazor 19.1.0.57.

I have two problems one of which may be a bug.

1- I try to use SfDatePicker in a GridColumn/Template for a date field, when ever its value is changed and tried to save it sends null object to web api post or update methods.If no change is made in Date field then it saves without problem.
This can be a bug, can you please check if it works on 19.1.0.57 version for odata/web api crud?

2- I cannot make cascading dropdowns work for odata/web api and could not find an example for odata/web api cascading dropdowns fro blazor.

My razor component is like as follows:

<SfGrid @ref="Grid" TValue="Dealer">
    <SfDataManager Url="odata/Dealers" Adaptor="Adaptors.ODataV4Adaptor" />
    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" ShowDeleteConfirmDialog="true" Mode="EditMode.Dialog" />
    <GridColumns>
        ...
    </GridColumns>

    <GridTemplates>
        <DetailTemplate>
            @{
                Dealer dealer = context as Dealer;
                DealerSetupLocation CurrentDealerSetupLocation = null;
                string DistrictsUrl = null;
                bool districtsIsEnabled = false;
            }
            <SfGrid @ref="DSLGrid" TValue="DealerSetupLocation" Query="@(new Query().Where("DealerId", "equal", dealer.CompanyId))">
                <SfDataManager Url="odata/DealerSetupLocations" Adaptor="Adaptors.ODataV4Adaptor" />
                <GridEvents TValue="DealerSetupLocation"
                            OnActionComplete=@((args) =>
                            {
                                CurrentDealerSetupLocation = args.Data;

                                if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.Add))
                                {
                                    CurrentDealerSetupLocation.DealerId = dealer.CompanyId;
                                }

                                DistrictsUrl = $"odata/Districts?$filter=ProvinceId eq {CurrentDealerSetupLocation?.ProvinceId}";
                                districtsIsEnabled = true;
                            })
                            OnActionBegin=@((args) =>
                            {
                                if (args.RequestType == Syncfusion.Blazor.Grids.Action.BeginEdit)
                                {
                                    districtsIsEnabled = false;
                                }
                            })  />
                <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" ShowDeleteConfirmDialog="true" Mode="EditMode.Dialog" />
                <GridColumns>
                    <GridColumn Field=@nameof(DealerSetupLocation.Id) IsPrimaryKey="true" Visible="false" ShowInColumnChooser="false" ShowColumnMenu="false" Width="0" />
                    <GridColumn Field=@nameof(DealerSetupLocation.ProvinceName) [email protected] EditType="EditType.DropDownEdit" AutoFit="true">
                        <EditTemplate Context="DealerSetupLocation">
                            <SfDropDownList ID="ProvinceId" @[email protected] TItem="Province" TValue="int" AllowFiltering="true" EnableVirtualization="true" FloatLabelType="FloatLabelType.Always" [email protected]>
                                <SfDataManager Url="odata/Provinces" Adaptor="Adaptors.ODataV4Adaptor" />
                                <DropDownListFieldSettings Text="Name" Value="Id" />
                                <DropDownListEvents TItem="Province" TValue="int"
                                    ValueChange=@((args) =>
                                    {
                                        CurrentDealerSetupLocation.District = null;
                                        DistrictsUrl = $"odata/Districts?$filter=ProvinceId eq {args.Value};";
                                        districtsIsEnabled = true;
                                        DSLGrid.PreventRender(false);
                                    }) />
                            </SfDropDownList>
                        </EditTemplate>
                    </GridColumn>
                    <GridColumn Field=@nameof(DealerSetupLocation.DistrictName) [email protected] AutoFit="true">
                        <EditTemplate Context="DealerSetupLocation">
                            <SfDropDownList ID="DistrictId" @[email protected] TItem="District" TValue="int?" FloatLabelType="FloatLabelType.Always" [email protected] ShowClearButton="true" Enabled="@districtsIsEnabled">
                                <SfDataManager Url=@DistrictsUrl Adaptor="Adaptors.ODataV4Adaptor" />
                                <DropDownListFieldSettings Text="Name" Value="Id" />
                            </SfDropDownList>
                        </EditTemplate>
                    </GridColumn>
                </GridColumns>
            </SfGrid>
        </DetailTemplate>
    </GridTemplates>
</SfGrid>

@code{
    protected SfGrid<Dealer> Grid { get; set; }
    protected SfGrid<DealerSetupLocation> DSLGrid { get; set; }
}

Example Models:

    public partial class Dealer
    {
        public Guid CompanyId { get; set; }        
        public virtual ICollection<DealerSetupLocation> DealerSetupLocations { get; set; }
    }

    public partial class DealerSetupLocation
    {
        public Guid Id { get; set; }
        public Guid DealerId { get; set; }
        public int ProvinceId { get; set; }
        public int? DistrictId { get; set; }

        public virtual Dealer Dealer { get; set; }
        public virtual District District { get; set; }
        public virtual Province Province { get; set; }
    }

    public partial class Province
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<DealerSetupLocation> DealerSetupLocations { get; set; }
        public virtual ICollection<District> Districts { get; set; }
    }

    public partial class District
    {
        public int Id { get; set; }
        public int ProvinceId { get; set; }
        public string Name { get; set; }

        public virtual Province Province { get; set; }
        public virtual ICollection<DealerSetupLocation> DealerSetupLocations { get; set; }
        public virtual ICollection<SubDistrict> SubDistricts { get; set; }
    }

In above razor file
DSLGrid.PreventRender(false);
causes null reference exception and if i conet it then the second dropdown does not change Url.

Can you please direct me to an odata/web api cascading dropdown example if any? I could not find any.

Thanks.

6 Replies 1 reply marked as answer

RS Renjith Singh Rajendran Syncfusion Team April 29, 2021 12:09 PM UTC

Hi Ali, 

Greetings from Syncfusion support. 

Query 1 : I try to use SfDatePicker in a GridColumn/Template for a date field, when ever its value is changed and tried to save it sends null object 
We suggest you to ensure to provide proper ID value for the SfDatePicker component inside EditTemplate of Grid. The ID property value should be similar to the Field value. And also ensure your codes based on the below documentation reference. 
 
 
        <GridColumn Field=@nameof(Order.OrderDate) ... Type="ColumnType.Date"> 
            <EditTemplate> 
                <SfDatePicker ID="OrderDate" @bind-Value="@((context as Order).OrderDate)" ...> 
                    ... 
                </SfDatePicker> 
            </EditTemplate> 
        </GridColumn> 
 
 
If you are still facing difficulties, kindly share with us the complete code example of using SfDatePicker in Grid. 

Query 2 : I cannot make cascading dropdowns work for odata/web api and could not find an example for odata/web api cascading dropdowns fro blazor. 
We suggest you to modify the codes based on the below suggestions to overcome the reported problem. We have also prepared a sample based on your requirement, please download the sample from the link below, 

Please find the list of modifications(total 3 points) suggested from our side. 

  1. Place the defining codes under @code section instead of using it inside DetailTemplate. Please refer and modify based on the below highlighted codes.

 
<SfGrid @ref="Grid" TValue="Dealer"> 
    ...  
    <GridTemplates> 
        <DetailTemplate> 
            @{ 
                Dealer dealer = context as Dealer; 
                //Place the codes which you have used here under code section
            } 
            ... 
        </DetailTemplate> 
    </GridTemplates> 
</SfGrid> 
 
@code{ 
    protected SfGrid<Dealer> Grid { getset; } 
        //Codes which you have used inside DetailTemplate
    DealerSetupLocation CurrentDealerSetupLocation = null; 
    string DistrictsUrl = null; 
    bool districtsIsEnabled = false; 
 
    ... 
} 


  1. Provide corresponding ref values for the Grid’s generated inside DetailTemplate. Use the below codes to define the @ref for Grid inside DetailTemplate. We have used DetailDataBound event of parent grid to generate a unique valued @ref for the corresponding grids generated using DetailTemplate.

<GridEvents TValue="Dealer" DetailDataBound="DetailDataBoundHandler"></GridEvents><GridTemplates>        <DetailTemplate>            @{                Dealer dealer = context as Dealer;                //Place the codes which you have used here under code section            }            <SfGrid @ref="myComponents[id]" TValue="DealerSetupLocation" >                <SfDataManager Url="odata/DealerSetupLocations" Adaptor="Adaptors.ODataV4Adaptor" />                ...                <GridColumns>                    <GridColumn Field=@nameof(DealerSetupLocation.ProvinceName) HeaderText="ProvinceLabel" ...>                        <EditTemplate Context="DealerSetupLocation">                            <SfDropDownList ID="ProvinceName" ...>                                ...                                <DropDownListEvents TItem="Province" TValue="int"                                           ValueChange=@((args) =>                   {                     CurrentDealerSetupLocation.District = null;                     ...                     //Use the unique ref generated for the corresponding Grid generated using DetailTemplate                     myComponents[dealer.Id.ToString()].PreventRender(false);                   }) />                            </SfDropDownList>                        </EditTemplate>                    </GridColumn>@code{    ...    public string id { getset; }    //for storing Detail Grid  reference dynamically     private Dictionary<string, SfGrid<DealerSetupLocation>> myComponents = new Dictionary<string, SfGrid<DealerSetupLocation>>();      public void DetailDataBoundHandler(DetailDataBoundEventArgs<Dealer> args)    {        id = args.Data.Id.ToString();     //set detail Grid id for ref when opening detail Grid     }}

  1. Use the Query property of SfDropDown to update the DataSource of second Dropdown instead of modifying the Url property of SfDataManager. Please refer the codes below,

<GridColumns>    <GridColumn Field=@nameof(DealerSetupLocation.ProvinceName) ...>         <EditTemplate Context="DealerSetupLocation">            <SfDropDownList ID="ProvinceName" ...>                ...                <DropDownListEvents TItem="Province" TValue="int"                ValueChange=@((args) =>                                {                                    CurrentDealerSetupLocation.District = null;                                    districtsIsEnabled = true;                                    //DistrictsUrl = $"odata/Districts?$count=true&$filter=(Id eq {args.Value})";                                    DistrictsQuery = new Query().Where("Id""equal", args.Value);                                    myComponents[dealer.Id.ToString()].PreventRender(false);                                }) />            </SfDropDownList>        </EditTemplate>    </GridColumn>    <GridColumn Field=@nameof(DealerSetupLocation.DistrictName) HeaderText="DistrictLabel" AutoFit="true">        <EditTemplate Context="DealerSetupLocation">                <SfDropDownList ... Query="@DistrictsQuery" TValue="int?" ...>                    <SfDataManager Url="odata/Districts" Adaptor="Adaptors.ODataV4Adaptor" />                    <DropDownListFieldSettings Text="Name" Value="Id" />                </SfDropDownList>        </EditTemplate>    </GridColumn></GridColumns>
@code{    Query DistrictsQuery = new Query();    ...}

Please get back to us if you need further assistance. 

Regards, 
Renjith R 


Marked as answer

AA ali arslan April 29, 2021 04:51 PM UTC

Hello Renjith,

Thank you very much for your detailed answer and code sample for casdading dropdownlist. It works fine. Before making any selection for Province, DistrictsQuery was null so it was listing all Districts without Province filter, to update DistrictsQuery before edit dialog is opened for DealerSetupLocation i made following change:

                    <SfGrid @ref="myComponents[id]" TValue="DealerSetupLocation" Query="@(new Query().Where("DealerId", "equal", dealer.CompanyId))">
                        <SfDataManager Url="odata/DealerSetupLocations" Adaptor="Adaptors.ODataV4Adaptor" />
                        <GridEvents TValue="DealerSetupLocation"
                                    OnActionComplete=@((args) =>
                                    {
                                        CurrentDealerSetupLocation = args.Data;

                                        if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.Add))
                                        {
                                            CurrentDealerSetupLocation.DealerId = dealer.CompanyId;
                                        }
                                        
                                         // update district query to filter districts for current province
                                        DistrictsQuery = new Query().Where("ProvinceId", "equal", CurrentDealerSetupLocation?.ProvinceId);
                                    })

It may be helpful for others having difficulty.


For SfDatePicker, still have problem. To see where the problem is i made a project and tested DateTime with a custom model and it was working fine, then added added and sql server table with exact same fields this time it wasnt working. I am attaching project,

Here 

    [Table("Person")]
    public partial class Person
    {
        [Key]
        public Guid Id { get; set; }
        [Required]
        [StringLength(50)]
        public string Name { get; set; }
        [Column(TypeName = "date")]
        public DateTime? BirthDate { get; set; }
    }

in Shared.Models folder is a database model,

and
    public partial class PersonModel
    {
        [Key]
        public Guid Id { get; set; }
        public string Name { get; set; }
        public DateTime? BirthDate { get; set; }
    }

is a custom model.
Added conreollers for both, PeopleController (for db model), PersonModelsController (for custom nodel)

If you can make an SQL Server database with name TestDb and add table named Person with above fields and some records in table you can see grids for both controllers on Index.razor.

ConnectionString is in appsettings.json, you may need to change it for your database.

If you make changes in BirthDate field abd save you will see that it works for PersonModel but not for Person.

I don't know where the problem is. I hope you can have time to have look at it.

Regards.
Ali A.




AA ali arslan April 29, 2021 04:58 PM UTC

Sorry, forgot to add project
Attached: ODataV4AdapterWithDateTime

Regards

Attachment: ODataV4AdapterWithDateTime_48978daf.zip


AA ali arslan April 30, 2021 07:49 PM UTC

Hello,

The proplem is with annotation  [Column(TypeName = "date")]

    [Table("Person")]
    public partial class Person
    {
        [Key]
        public Guid Id { get; set; }
        [Required]
        [StringLength(50)]
        public string Name { get; set; }
        //[Column(TypeName = "date")]
        public DateTime? BirthDate { get; set; }
    }

if it is commented out then it works.

Regards.


RS Renjith Singh Rajendran Syncfusion Team May 5, 2021 04:08 AM UTC

Hi Ali, 

We are able to reproduce the reported problem from our side. As we are not certain about, whether the reported problem is related to Grid or OData side, we are currently validating this scenario to find the root cause.  

We will update you further details in two business days. Until then we appreciate your patience. 

Regards, 
Renjith R 



RS Renjith Singh Rajendran Syncfusion Team May 6, 2021 12:23 PM UTC

Hi Ali, 

We have considered it as a usability improvement and logged a task “Date format serialization support in posted data”. At the planning stage for every release cycle, we review all open features and identify features for implementation based on specific parameters including product vision and technological feasibility. We will implement this feature in any of our upcoming releases. 
  
You can also communicate with us regarding the open features any time using our Feature Report page.     

Regards, 
Renjith R 


Loader.
Up arrow icon