Is there a way to make the grid show rows with no data?

Hi, I have been working on a Blazor server app and have created a grid to show my data. I added some filter columns to limit the grid to only show one week at a time, as can be seen below in the screenshots. However, if there is only data for  some of the days in the database, the grid only shows those days of entries. Is there a way to make the grid always show a full week, even if there are no entries for some of the days? Particularly, I would like it to show a custom message on rows with no data, like perhaps a button to add an entry for that date.
This is how it is.  and below is how I would like it to be

below is the code I used for the grid for this sample.



4 Replies 1 reply marked as answer

RN Rahul Narayanasamy Syncfusion Team June 16, 2021 02:49 PM UTC

Hi Nathan, 

Greetings from Syncfusion. 

Query: Is there a way to make the grid show rows with no data? 

We have validated your query and you want to show empty data in Grid while performing grouping operation. You can add the empty data in Grid while Grouping by using CustomAdaptor. Here, we have added the empty data(only primary key value and data value present) to Grid at initial grouping. Find the below code snippets for your reference. 

 
<SfGrid TValue="Order" ID="Grid" AllowGrouping="true" AllowFiltering="true" AllowPaging="true" 
        Toolbar="@(new List<string>() { "Add", "Delete", "Update", "Cancel" })"> 
    <GridGroupSettings Columns="@((new string[] { "OrderDate" }))"></GridGroupSettings> 
    <SfDataManager AdaptorInstance="@typeof(CustomAdaptor)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager> 
    <GridPageSettings PageSize="8"></GridPageSettings> 
    <GridColumns> 
        <GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" Visible="false" IsPrimaryKey="true" TextAlign="@TextAlign.Center" Width="140"></GridColumn> 
        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn> 
        <GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="ddd MMMM d yyyy" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn> 
        <GridColumn Field=@nameof(Order.City) HeaderText="City" Width="150"></GridColumn> 
    </GridColumns> 
</SfGrid> 
 
@code{ 
    public static List<Order> Orders { get; set; } 
    static int IdValue { get; set; } = 2000; 
    static List<Order> newData = new List<Order>() { 
                new Order() { OrderID = IdValue++, OrderDate = DateTime.Now.AddDays(1) }, 
                new Order() { OrderID = IdValue++, OrderDate = DateTime.Now.AddDays(1) }, 
                new Order() { OrderID = IdValue++, OrderDate = DateTime.Now.AddDays(2) } 
                };    //added primary key value and data value alone. Since primary key value is required for editing. 
 
    . . . 
 
    // Implementing custom adaptor by extending the DataAdaptor class 
    public class CustomAdaptor : DataAdaptor 
    { 
        // Performs data Read operation 
        public override object Read(DataManagerRequest dm, string key = null) 
        { 
            IEnumerable<Order> DataSource = Orders; 
            . . . 
 
            int count = DataSource.Cast<Order>().Count(); 
            if (dm.Skip != 0) 
            { 
                //Paging 
                DataSource = DataOperations.PerformSkip(DataSource, dm.Skip); 
            } 
            if (dm.Take != 0) 
            { 
                DataSource = DataOperations.PerformTake(DataSource, dm.Take); 
            } 
            DataResult DataObject = new DataResult(); 
            if (dm.Group != null) 
            { 
                DataSource = DataSource.Concat(newData);    //added new empty data(only primary key value and data value present) while grouping 
                IEnumerable ResultData = DataSource.ToList(); 
                // Grouping 
                foreach (var group in dm.Group) 
                { 
                    ResultData = DataUtil.Group<Order>(ResultData, group, dm.Aggregates, 0, dm.GroupByFormatter); 
                } 
                DataObject.Result = ResultData; 
                DataObject.Count = count; 
                return dm.RequiresCounts ? DataObject : (object)ResultData; 
            } 
            return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource; 
        } 
 
    } 
} 
 


[Screenshot] 
 


Reference: 

If you want to edit the empty data, use Editing feature of the Grid. Editing feature requires Primary column. Find the below link for reference. 

For handling editing in custom adaptor find the below link. 

Please let us know if you have any concerns. 

Regards, 
Rahul 



NL Nathan Lockwood June 17, 2021 09:56 PM UTC

Hi Rahul,
Thanks for responding in regards to my post.

I applied the suggested solution and got it somewhat working, however I have run into the issue of the empty rows being out of order from the rest of the data. 
As you can see above, the empty entries are just being added to the bottom, and arent being put in place with the other ones. I tried to make sure that I had sorting enabled in my grid, with appropriate sorting columns, but it just sorts all the other data and ignores the empty rows. Additionally, If I have an entire week of empty entries, and I change the date filter to show a different week, the program throws the following exception: 
System.InvalidOperationException: This operation is only valid on generic types.
   at System.RuntimeType.GetGenericTypeDefinition()
   at Syncfusion.Blazor.Grids.SfGrid`1.IsObservableCollection(Object data)
   at Syncfusion.Blazor.Grids.SfGrid`1.CollectionDisposeMethod(Object data)
   at Syncfusion.Blazor.Grids.SfGrid`1.System.IDisposable.Dispose()
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.Dispose()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.Dispose(Boolean disposing)

This error only started happening after I added the empty data. and only seems to happen if the grid is only showing empty entries when somethings dispose method gets called.

Some things that I did that might help explain this problem are as follows: 
In order to know which rows had data and which didn't I created a the following method and bound it to the grids OnDataBound event.

 //adds up to 7 entries to the data before being bound to the graph to show empty rows for days with no data.
        private void AddEmptyEntries(BeforeDataBoundArgs<HoursWorked> args)
        {
            if (TimecardGrid is null)
                return;
            List<HoursWorked> result = new List<HoursWorked>();
            List<DateTime> entryDates = args.Result.Select(o => (o as HoursWorked).Date.Date).ToList();
            DateTime date = (DateTime)GetSelectedDate();
            for (DateTime Start = date.AddDays(-(int)(date).DayOfWeek); Start <date.AddDays(7); Start = Start.AddDays(1)) //gets the start of the week and iterates through the week
            {
                if (!entryDates.Contains(Start.Date))
                {
                    result.Add(new HoursWorked { Date = Start.Date, Id = 0, ... //more fields here });
                }
            }
            Emptyrows = result;
            return;
        }

The EmptyRows that gets set at the bottom is a global variable in my timecard page that gets passed as a parameter into my custom adaptor and used in place of your newdata variable as shown below.

//code above
...
if (dm.Group != null)
        {
            //Grouping
            data = data.Concat<T>(EmptyData);
            IEnumerable GroupData = Enumerable.Empty<T>();
            foreach (var group in dm.Group)
            {
                GroupData = DataUtil.Group<T>(data, group, dm.Aggregates, 0, dm.GroupByFormatter);
            }
            DataObject.Result = GroupData;
            DataObject.Count = data.Count();
            return dm.RequiresCounts ? DataObject : (object)GroupData;
        }
...
//code below


NL Nathan Lockwood replied to Nathan Lockwood June 23, 2021 10:11 PM UTC

An addendum to my last reply, Additionally, the grid event that I currently have the AddEmptyEntries bound to is not an ideal one, as there are several operations which cause the empty entries to disappear until the ondatabound event gets called again. Is there a different event or state that I can bind this function to? I just want the empty entries to be populated in the grid right before the week renders, but after the data has been retrieved, so that I know what days to add empty entries on.



RN Rahul Narayanasamy Syncfusion Team June 24, 2021 12:44 PM UTC

Hi Nathan, 

Thanks for the update. 

We have validated your query with the provided details and we suspect that the added empty rows are not being added in the corresponding grouping order. We suggest you to add the new empty data in before sorting (dm.Sorted) portion like the below code snippets. Now the empty rows are added in correct grouped order. Find the below code snippets and sample for your reference. 

// Implementing custom adaptor by extending the DataAdaptor class 
    public class CustomAdaptor : DataAdaptor 
    { 
        // Performs data Read operation 
        public override object Read(DataManagerRequest dm, string key = null) 
        { 
            IEnumerable<Order> DataSource = Orders; 
            if (dm.Search != null && dm.Search.Count > 0) 
            { 
                // Searching 
                DataSource = DataOperations.PerformSearching(DataSource, dm.Search); 
            } 
            if (dm.Sorted != null && dm.Sorted.Count > 0) 
            { 
                if (dm.Group != null) 
                { 
                    DataSource = DataSource.Concat(newData);    //add the empty data here instead of adding in dm.Group 
                } 
                // Sorting 
                DataSource = DataOperations.PerformSorting(DataSource, dm.Sorted); 
            } 
            . . . 
            DataResult DataObject = new DataResult(); 
            if (dm.Group != null) 
            { 
                //DataSource = DataSource.Concat(newData);     //remove this line from here 
                IEnumerable ResultData = DataSource.ToList(); 
                // Grouping 
                foreach (var group in dm.Group) 
                { 
                    ResultData = DataUtil.Group<Order>(ResultData, group, dm.Aggregates, 0, dm.GroupByFormatter); 
                } 
                DataObject.Result = ResultData; 
                DataObject.Count = count; 
                return dm.RequiresCounts ? DataObject : (object)ResultData; 
            } 
            return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource; 
        } 
 
    } 
} 

 


Also, we are not quite clear about the error while changing the filter. Could you please share more information(Video demonstration, Simple issue reproduceable sample or reproduce the problem in the provided sample and revert back to us) about this problem. It will be helpful to validate and provide a better solution. 

Query: Additionally, the grid event that I currently have the AddEmptyEntries bound to is not an ideal one, as there are several operations which cause the empty entries to disappear until the ondatabound event gets called again. 

We suspect that the method you have defined in DataBound event is called again and again when you perform data operation. We would like to inform you that the DataBound event will be called each time when we perform data operations and other operation(like paging).  

If you want to call this method at initial rendering itself, then could you please check Created and OnLoad event of the Grid. 

Reference: 

If we misunderstood your problem, then please share more information about your requirement. It will be helpful to validate and provide a better solution. 

Please let us know if you have any concerns. 

Regards, 
Rahul 


Marked as answer
Loader.
Up arrow icon