Strange Behavior after Adding new Row

I have a grid that is bound through a CustomAdaptor.  When I add a new row as per the following... 


I see the Edit Row and add my data then press Update...


... and I see the newly added row, all good so far.. But when I attempt to add a second row...


.. I don't get the Edit Row.. but the Update and Cancel Buttons are enabled...


If I press Cancel nothing happens (Update and Cancel remain enabled).  If I press Update, I see a new Row with no text...


At which point I can no longer select a row in the data grid.  

If I change to Dialog model it pops up the edit window each time and I can add new rows, but I still can't select any rows.


I use the data grid a lot but this is the first time I am seeing such an issue.   

<SfGrid @ref="_gridView" TValue="ValidatorClientViewModel" ID="ValidatorTreeView" Query="QueryData" AllowSorting="true"

        AllowPaging="true" Toolbar="@ToolbarItems" Width="AutoWidth">

    <GridTemplates>

        <EmptyRecordTemplate>

            <span>No Selected Aggregates</span>

        </EmptyRecordTemplate>

    </GridTemplates>

    <GridSelectionSettings Type="Syncfusion.Blazor.Grids.SelectionType.Multiple"></GridSelectionSettings>

    <SfDataManager @ref="DataManager" AdaptorInstance="@typeof(ValidatorsDataAdaptorModel)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager>

    <GridPageSettings PageSize="5"></GridPageSettings>

    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="Syncfusion.Blazor.Grids.EditMode.Normal"></GridEditSettings>

    <GridEvents OnBeginEdit="OnBeginEdit" OnActionFailure="OnActionFailure" OnActionBegin="OnActionBegin" OnActionComplete="OnActionComplete"

                OnBatchAdd="OnBatchAdd" RowSelected="RowSelecthandler" TValue="ValidatorClientViewModel"> </GridEvents>

    <GridColumns>

        <GridColumn Field="Validator.ValidatorId.Id" HeaderText="Id" IsPrimaryKey="true" Visible=false Width="0"></GridColumn>

        <GridColumn Field="Validator.ValidatorName" HeaderText="Validator Name" Width="50" ValidationRules="@(new Syncfusion.Blazor.Grids.ValidationRules { Required = true })"></GridColumn>

    </GridColumns>

</SfGrid>


7 Replies

RS Renjith Singh Rajendran Syncfusion Team July 5, 2021 12:21 PM UTC

Hi John, 

Greetings from Syncfusion support. 

We are not clear about the exact scenario you are facing this reported problem. We suggest you to ensure to handle the CRUD methods in ValidatorsDataAdaptorModel class in your application. 

If you are still facing difficulties, then the following details would be helpful for us to proceed further. 

  1. Share the details of any exception if any occurred in the browser console when pressing Add button.
  2. Share the complete model class(ValidatorClientViewModel, Validator, ValidatorId) codes you are using for complex binding in grid.
  3. Share the complete CustomAdaptor class(ValidatorsDataAdaptorModel) codes.
  4. If possible share with us a simple issue reproducing sample for us to validate based on your scenario.
  5. Share the exact scenario you are facing this reported problem.
  6. Bind OnActionFailure event to grid, and share the details you get in the args of this event handler.

The provided information will help us analyze the problem, and provide you a solution as early as possible. 

Regards, 
Renjith R 



JO John August 5, 2021 10:14 AM UTC

This took me a long time to figure out this odd behavior that I was experiencing and it's super easy to reproduce.

In my case there was nothing wrong with my custom data adaptor however the data that I was returning was originally derived from a List that is in a backing ViewModel that my custom data adaptor integrates with to acquire data from a back-end service.

I recently altered that backing ViewModel to derive from ReactiveObject (ReactiveUI) and in the process altered the backing collection from List to ObservableCollection to aid in collection-based change detection.

As such, the ReadAsync operation in my Custom Adaptor returned this collection of ObservableCollection which you DataManager seemingly can't handle.


To reproduce my issue, create a similar data adaptor as per the one below and bind to a DataGrid....


public class Test

{

public string Id;

public string Name;


}

public partial class TestAdaptorModel : Syncfusion.Blazor.DataAdaptor

{


ObservableCollection _fake = new ObservableCollection();


public override async Task<object> ReadAsync(DataManagerRequest dmr, string key = null)

{

return new DataResult()

{ Result = _fake, Count = _fake.Count };

}


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

{

_fake.Add(value as Test);

return value;

}


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

{

return value;

}


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

{

foreach (var vm in _fake)

{

if (vm.Id.Equals(value.ToString()))

{

_fake.Remove(vm);

return null;

}

}

return null;

}

}


In my actual custom data adaptor I cast the backing ObservableCollection<T>  back to a List<T> in the ReadAsync method which seems to resolve my issue.  Can you explain this behavior please?



here is my full custom data adaptor...


using Autofac;

using Microsoft.AspNetCore.Components;

using Serilog;

using Syncfusion.Blazor;

using Syncfusion.Blazor.Data;

using System;

using System.Linq;

using System.Threading.Tasks;

using NextWare.Infrastructure.DDD;

using System.Collections.Generic;

using System.ComponentModel;

using Splat;

using AutoMapper;

using NextWare.Infrastructure.BaseViewModel;

using NextWare.Domain.ValidationServices.Validator.ClientViewModels;



namespace NextWare.Domain.ValidationServices.Validator.DataAdaptors

{

    public partial class ValidatorsDataAdaptorModel : Syncfusion.Blazor.DataAdaptor, IViewModelCollection<ValidatorClientViewModel, ValidatorsClientViewModel>

    {


        private string _lastEditedId;

        public ISearchResponse<ValidatorClientViewModel> SearchResponse

        {

            get;

            private set;

        }


        public ValidatorsClientViewModel CientViewModel

        {

            get;

            private set;

        }


        private Guid _adaptorID = Guid.NewGuid();

        private IMapper _mapper;

        public ValidatorsDataAdaptorModel()

        {

            _mapper = Locator.Current.GetService<IMapper>();

            Log.Information("Created DataAdaptor for Validators {adaptorID}", _adaptorID.ToString());

        }


        public void AssignViewModel(ValidatorsClientViewModel vm)

        {

            CientViewModel = vm;

            SearchResponse = CientViewModel as ISearchResponse<ValidatorClientViewModel>;

        }


        public override async Task<object> ReadAsync(DataManagerRequest dmr, string key = null)

        {

            try

            {

                if (CientViewModel == null)

                    return new DataResult()

                    {Result = new List<DataResult<ValidatorClientViewModel>>(), Count = 0};


                Log.Information("Started ReadAsync for Validators {adaptorID}", _adaptorID.ToString());

                long count = 0;


                await CientViewModel.ExecuteQueryAsync(_mapper.Map<NextWare.Client.Infrastructure.Elastic.DataManagerRequest>(dmr), _lastEditedId);


                _lastEditedId = null;


                // Total documents in Elastic

                count = CientViewModel.TotalDocuments;


                IEnumerable<ValidatorClientViewModel> dataSource = CientViewModel.Validators;

                if (dmr.Sorted != null && dmr.Sorted.Count > 0)

                {

                    // Sorting

                    dataSource = DataOperations.PerformSorting(CientViewModel.Validators, dmr.Sorted);

                }


                SearchResponse = CientViewModel as ISearchResponse<ValidatorClientViewModel>;


                // return response

                var readResponse = dmr.RequiresCounts ? new DataResult()

                { Result = CientViewModel.Validators.ToList(), Count = Convert.ToInt32(count)} : (object)CientViewModel.Validators.ToList();


                Log.Information("Started ReadAsync for Validators {adaptorID}", _adaptorID.ToString());

                return readResponse;

            }

            catch (Exception ex)

            {

                Log.Error("Exception trying to ReadAsync { ex} for Validators", ex);

            }


            return null;

        }


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

        {

            try

            {

                if (value == null)

                    return value;


                Log.Information("Started InsertAsync for Validators {adaptorID}", _adaptorID.ToString());



                var vm = value as ValidatorClientViewModel;

                _lastEditedId = vm.Validator.ValidatorId.Id; // when data is added or updated, we need to get the last page on next search


                await CientViewModel.InsertValidatorClientViewModel(vm);

                Log.Information("Completed InsertAsync for Validators {adaptorID}", _adaptorID.ToString());

                return vm;

            }

            catch (Exception ex)

            {

                Log.Error("Exception trying to add { ex}", ex);

            }


            return value;

        }


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

        {

            try

            {

                if (value == null)

                    return value;

                Log.Information("Started UpdateAsync for Validators {adaptorID}", _adaptorID.ToString());

                var vm = value as ValidatorClientViewModel;

                _lastEditedId = vm.Validator.ValidatorId.Id; // when data is added or updated, we need to get the last page on next search

                await CientViewModel.UpdateValidatorClientViewModel(vm);

                Log.Information("Completed UpdateAsync for Validators {adaptorID}", _adaptorID.ToString());

                return vm;

            }

            catch (Exception ex)

            {

                Log.Error("Exception trying to update {ex}", ex);

            }


            return value;

        }


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

        {

            try

            {

                if (value == null)

                    return value;

                Log.Information("Started RemoveAsync for Validators {adaptorID}", _adaptorID.ToString());

                await CientViewModel.DeleteValidatorClientViewModel(value.ToString());

                Log.Information("Completed RemoveAsync for Validators {adaptorID}", _adaptorID.ToString());

                return null;

            }

            catch (Exception ex)

            {

                Log.Error("Exception trying to delete {Id} {ex} for Validators", value.ToString(), ex);

            }


            return null;

        }


        public override async Task SetParametersAsync(ParameterView parameters)

        {

            Log.Information("Started SetParametersAsync for Validators {adaptorID}", _adaptorID.ToString());

            await base.SetParametersAsync(parameters);

            Log.Information("Started SetParametersAsync for Validators {adaptorID}", _adaptorID.ToString());

        }


        public override async Task<object> BatchUpdateAsync(DataManager dataManager, object changedRecords, object addedRecords, object deletedRecords, string keyField, string key, int? dropIndex)

        {

            try

            {

                Log.Information("Started BatchUpdateAsync for Validators {adaptorID}", _adaptorID.ToString());

                if (addedRecords != null)

                {

                    foreach (var vm in (IEnumerable<ValidatorClientViewModel>)addedRecords)

                    {

                        Log.Information("Started InsertValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                        await CientViewModel.InsertValidatorClientViewModel(vm);

                        Log.Information("Completed InsertValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                    }

                }


                if (changedRecords != null)

                {

                    foreach (var vm in (IEnumerable<ValidatorClientViewModel>)changedRecords)

                    {

                        Log.Information("Started UpdateValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                        await CientViewModel.UpdateValidatorClientViewModel(vm);

                        Log.Information("Completed UpdateValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                    }

                }


                if (deletedRecords != null)

                {

                    foreach (var vm in (IEnumerable<ValidatorClientViewModel>)deletedRecords)

                    {

                        Log.Information("Started DeleteValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                        await CientViewModel.DeleteValidatorClientViewModel(vm.Validator.ValidatorId.Id);

                        Log.Information("Completed DeleteValidatorClientViewModel for Validators {adaptorID}", _adaptorID.ToString());

                    }

                }


                Log.Information("Completed BatchUpdateAsync for Validators {adaptorID}", _adaptorID.ToString());

                return changedRecords;

            }

            catch (Exception ex)

            {

                Log.Error("Exception {ex} BatchUpdateAsync for Validators", ex);

            }


            return null;

        }

    }

}



JO John August 5, 2021 06:00 PM UTC

I noticed that where I am only assigning the DataSource of a DataGrid to ObservableCollection<T> they do not seem to have the same issue as does via the Custom DataAdaptor inte



RS Renjith Singh Rajendran Syncfusion Team August 9, 2021 02:12 PM UTC

Hi John, 

We are able to reproduce the reported problem from our side. We are currently validating this scenario. 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 August 10, 2021 12:39 PM UTC

Hi John, 

We have confirmed it as a bug and logged the defect report Problem with Add records when define CustomAdaptor to return ObservableCollection from Read method” for the same. Thank you for taking the time to report this issue and helping us improve our product. At Syncfusion, we are committed to fixing all validated defects (subject to technological feasibility and Product Development Life Cycle) and including the defect fix in our weekly release which is expected to be rolled out by the mid of September, 2021.  
 
You can now track the current status of your request, review the proposed resolution timeline, and contact us for any further inquiries through this link.       

Regards, 
Renjith R 




RS Renjith Singh Rajendran Syncfusion Team October 5, 2021 03:22 AM UTC

Hi John, 

Sorry for the inconvenience caused. 

Due to some unforeseen circumstances, we have planned to include this in our upcoming bi-weekly release which is expected to be rolled out on or before the mid of October, 2021. 
  
Until then we appreciate your patience.  
  
Regards,  
Renjith R 



RS Renjith Singh Rajendran Syncfusion Team November 3, 2021 06:22 AM UTC

Hi John,   
 
We are glad to announce that our latest release(19.3.0.48) has been successfully rolled out. We have included the fix for this issue “Problem with Add records when define CustomAdaptor to return ObservableCollection from Read method” in our latest version release. So please upgrade to our latest release for latest fixes and features.  
 
We thank you for your support and appreciate your patience in waiting for this release. Please get in touch with us if you would require any further assistance.   
    
Regards,              
Renjith R  


Loader.
Up arrow icon