Updating the datasource to show changes in the grid

Hi,

I am having trouble with something that I think should be easy, so I must be doing something wrong.

I have created a grid, and bound it to a data source. I would expect that if I added more objects to the datasource, I could call "StateHasChanged" and the grid would update to show all of the elements in the data source .

In the example below I have created a button that
  • creates a new object
  • adds the object to the datasource
  • calls StateHasChanged() in the hope that the grid updates.

Simple example below

[code]
@page "/TestDataGridPage"

TestDataGridPage


        Toolbar="@(new List() { "Add", "Edit", "Delete", "Cancel", "Update" })"
        AllowFiltering="false" AllowSorting="false" AllowGrouping="false"
        Height="100">
 
                    Mode="EditMode.Normal" NewRowPosition="NewRowPosition.Bottom">
 
   
   
   
   
 

  Clear Grid
  Test
  AddItem
 

@code {
  SfGrid grid;

  string OutputTest { get; set; }

  private int currentId = 1;

  TestPageViewModel ViewModel { get; set; }

  public IEditorSettings ItemsEditParams = new NumericEditCellParams
  {
    Params = new NumericTextBoxModel() { ShowSpinButton = false, Decimals = 0 }
  };

  protected override async Task OnInitializedAsync()
  {
    ViewModel = new TestPageViewModel();
    await base.OnInitializedAsync();
  }

  public void OnTestButtonPressed()
  {
    OutputTest = "ListCount = " + ViewModel.ListItems.Count;
  }

  public void OnCancelButtonPressed()
  {
    ViewModel.ResetGridItems();
    OutputTest = "ListCount = " + ViewModel.ListItems.Count;
    StateHasChanged();
  }

  // here I an expecgting that as I add items to the datasource, they are displayed in the grid
  private void OnAddItemButtonPressed()
  {
    GridItemModel add = new GridItemModel();
    add.Id = currentId;
    add.Quantity = currentId;
    add.Description = "Description:" + currentId;
    StateHasChanged();
    currentId++;
  }

  private class TestPageViewModel
  {
    public List ListItems { get; set; }

    public TestPageViewModel()
    {
      ListItems = new List();
    }

    public void ResetGridItems()
    {
      //ListItems.Clear();
      ListItems = new List();
    }
  }

  private class GridItemModel
  {
    public int Id { get; set; }
    public int Quantity { get; set; }
    public string Unit { get; set; }
    public string Description { get; set; }
  }

}
[/code]

Regards,
Jeremy

9 Replies 1 reply marked as answer

RN Rahul Narayanasamy Syncfusion Team August 17, 2020 12:32 PM UTC

Hi Jeremy, 

Greetings from Syncfusion. 

Query: Updating the datasource to show changes in the grid, 

We have validated your query and you want to update the Grid datasource without using Grid default add/update operation. We suggest you to call Refresh the Grid after adding the created object in Grid DataSource. Find the below code snippets and sample for your reference. 

 
<button @onclick="OnAddItemButtonPressed">Add Data</button> 
<SfGrid @ref="Grid" DataSource="@Orders" AllowPaging="true"> 
    <GridPageSettings PageSize="10"></GridPageSettings> 
    <GridColumns> 
        <GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn> 
        . . . 
    </GridColumns> 
</SfGrid> 
 
@code{ 
    SfGrid<Order> Grid; 
    private int currentId = 123; 
    public List<Order> Orders { get; set; } 
 
    . . . 
    private void OnAddItemButtonPressed() 
    { 
        Order add = new Order(); 
        add.OrderID = currentId; 
        add.CustomerID = "Tokyo"; 
        add.OrderDate = new DateTime(2020, 04, 05); 
        add.Freight = 11.22; 
        Orders.Add(add);   //add the created object in Grid datasource. In your code, you have not added the created object in Grid Datasource 
        Grid.Refresh();   //calling Refresh method of Grid to show the added record 
        currentId++; 
    } 
} 


  • If you are using the observable collection, then you can directly add the records in DataSource. There is no need to call StateHasChanged or Refresh method of Grid to update the datasource(we have handled in our source for showing the added/edited data without calling StateHasChanged/Refresh method of Grid).
  • If you are using other than observable collection(like IEnumerable),  then you need to call Refresh method of the Grid to reflect the changes in Grid.

Please let us know if you have any concerns. 

Regards, 
Rahul 


Marked as answer

JE Jeremy August 18, 2020 01:10 PM UTC

Thanks Rahul,

thanks for pointing out both observable collection and refresh. I have tested both mechanisms and what I have aimed to implement is now working as expected.

Whilst on the topic of grids can I ask a few more quick questions please?

1) How do you control Readonly / Enabled of a grid (I couldnt seem to find these properties)

2) How do you make sure that a newly added row is added to the bottom of the grid
  • I found the NewRowPosition="NewRowPosition.Bottom" which is working great
  • but after I click update (and the row saves to the datasource) the newly saved row goes to the top of the grid.

Regards,
Jeremy


RN Rahul Narayanasamy Syncfusion Team August 19, 2020 12:10 PM UTC

Hi Jeremy, 
 
Thanks for the update. 
 
We are happy to hear that you have achieved your requirement. 
 
Query: How do you control Readonly / Enabled of a grid (I couldnt seem to find these properties) 
 
We have validated your query and we might suspect that you want to disable(readonly – not editable) editing for particular column. You can achieve your requirement by defining AllowEditing property as false in required column. Find the below code snippets for your reference. 
 
<SfGrid @ref="Grid" DataSource="@Orders" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })" AllowPaging="true"> 
    . . . 
        <GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn> 
        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" AllowEditing="false" Width="150"></GridColumn> 
        . . . 
    </GridColumns> 
</SfGrid> 
 
Reference: 
 
Query: I found the NewRowPosition="NewRowPosition.Bottom" which is working great but after I click update (and the row saves to the datasource) the newly saved row goes to the top of the grid. 
 
By default while adding a new row, the form will be render at top of the Grid. Using NewRowPosition property of Grid we can customize the form position to be either top or bottom and it will not determine the insert position of the new recordWhile clicking on the Add toolbar, add new row form will be rendered where we can input values. NewRowPosition property is used to determine the position of that form. 
 
Also, by default newly added record will be inserted at the first position only. If you want to insert the record at specific position other than first, then we suggest you to use any one of the adaptor or CustomAdaptor where CRUD action will be handled externally, hence we can customize / determine the position of inserted record.   
 
NewRowPosition property of GridEditSettings is used to determine the position of add row form.  
 
In the Counter.razor page, we have added the record at 11 position using CustomAdaptor. Find the below code snippets and sample for your reference. 
 
       // Performs Insert operation 
        public override object Insert(DataManager dm, object value, string key) 
        { 
            Orders.Insert(11, value as Order); 
            return value; 
        } 


Please let us know if you have any concerns. 

Regards, 
Rahul 



JE Jeremy August 23, 2020 11:31 PM UTC

Thanks Rahul,

No, I am trying to disable the entire grid from any actions. I want the grid to perform like any other control when I mark it as "readonly", ie
  • no ability to add, edit or delete any rows (so the buttons are disabled)
  • no ability to double click and start editing a row.
  • the font colour of the buttons in the header row got a lighter colour to indicate that they are not available to be used
  • the background colour of the grid changes colour to indicate that the entire grid is readonly.
I am not looking to make a change per column, I would like the entire grid control to be marked (and displayed) as either ready only or disabled.


"Also, by default newly added record will be inserted at the first position only."

What is the logic behind this? Normally if you add something to a list, it goes to the end of the list. So if I have a datasource tied to the grid, and I add a new object, that object will go at the end of the list, but at the start of the grid? I dont think that makes a lot of sense.

Thanks for the example, I will have a look when I next get a chance.

Regards,
Jeremy




RN Rahul Narayanasamy Syncfusion Team August 25, 2020 05:02 PM UTC

Hi Jeremy, 

Thanks for the update. 

Query: I am not looking to make a change per column, I would like the entire grid control to be marked (and displayed) as either ready only or disabled. 

We have validated your query and you want to disable the whole Grid without performing any actions in Grid. Here, we have achieved your requirement by using CSS. Find the below code snippets and sample for your reference. 

 
<SfButton @ref="ToggleBtn" @onclick="Disable" CssClass="e-flat" IsToggle="true" IsPrimary="true" Content="@Content"></SfButton> 
 
<div class=@ClassValue> 
    <SfGrid @ref="Grid" DataSource="@Orders" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })" AllowPaging="true"> 
        . . . 
   </SfGrid> 
</div> 
 
 
@code{ 
    SfButton ToggleBtn; 
    SfGrid<Order> Grid; 
    private int currentId = 123; 
    public string Content = "Disable"; 
    public string ClassValue { get; set; } 
    . . . 
   private void Disable(Microsoft.AspNetCore.Components.Web.MouseEventArgs args) 
    { 
        if (ToggleBtn.Content == "Disable") 
        { 
            ClassValue = "disable"//here, we have added class to disable  
            Content = "Enable"; 
        } 
        else 
        { 
            ClassValue = ""; 
            Content = "Disable"; 
        } 
    } 
} 
 
<style> 
    .disable { 
        pointer-events: none; 
        opacity: 0.4; 
    } 
</style> 


Query: So if I have a datasource tied to the grid, and I add a new object, that object will go at the end of the list, but at the start of the grid? I dont think that makes a lot of sense. 

Sorry for the inconvenience. 

We have validated your query and while adding the new data to List, it added the new data at the end of the list. In our Grid, while adding the record in Inline edit mode, the added record is inserted at the top(first position) of the Grid while saving the added record. 

NewRowPosition property of GridEditSettings is used to determine the position of add row form. If you want to insert the record at specific position other than first, then we suggest you to use any one of the adaptor or CustomAdaptor as we suggested in previous update. 
 
In the previously shared sample, in the Counter.razor page, we have added the record at 11 position using Insert method of CustomAdaptor. Find the below code snippets and sample for your reference.  
  
       // Performs Insert operation  
        public override object Insert(DataManager dm, object value, string key)  
        {  
            Orders.Insert(11, value as Order);  
            return value;  
        }  
 
Please let us know if you have any concerns. 
 
Regards, 
Rahul 



JE Jeremy August 26, 2020 06:09 AM UTC

Thanks Rahul,

the implementation of disabled grid was sufficient. I would be nice that disabled / readonly was a property of the grid control just like most other controls (input text, combo box) rather than having to implement CSS.

With regards to the sort order, can you provide an example of using a custom adaptor that does not require "orders" to be a static variable please? I have implemented a MVVM patter with my Model class being passed into the razor element as a parameter, ie

[Parameter]
public Models.IConsignmentModel ConsignmentModel { get; set; }


where the interface class is defined as

public interface IConsignmentModel : IDisposable
{
    List<ConsignmentLineDTO> Lines { get; set; }
}

and the datasource for me grid is 
DataSource="@ConsignmentModel.Lines"

(which I understand with an adaptor I will need to remove the datasource declaration, but how do I get the ConsignmentModel instance into the adaptor class?

Is it possible to create a concrete instance of the CustomAdaptor, and pass this concrete instance to the Grid?


RN Rahul Narayanasamy Syncfusion Team September 1, 2020 02:28 PM UTC

Hi Jeremy, 

Thanks for the suggestion. 

Query: the implementation of disabled grid was sufficient. I would be nice that disabled / readonly was a property of the grid control just like most other controls (input text, combo box) rather than having to implement CSS. 

Based on your request, we have considered this requirement as an usability improvement feature and logged the improvement report for the same. Thank you for taking the time to request this improvement “Need to provide support for Enabling and Disabling the Grid using Property” 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 improvement feature in any of our upcoming release. 
  
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.      
  

Until then we appreciate your patience.  

Query: can you provide an example of using a custom adaptor that does not require "orders" to be a static variable please? 

We have validated your query and we might suspect that you want to inject a service into Custom adaptor and use that to service to bind the data to Grid. You can achieve your requirement by Injecting the service. Find the below code snippets and sample for your reference. 

public class CustomAdaptor : DataAdaptor 
    { 
        [Inject] 
        public OrderDataAccessLayer context { get; set; } = new OrderDataAccessLayer(); 
        // Performs data Read operation 
        public override object Read(DataManagerRequest dm, string key = null) 
        { 
            IEnumerable<Order> DataSource = context.GetAllOrders(); 
            . . . 
            return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource; 
        } 
    } 


Reference

If it does not meet your requirement or if we misunderstood your query, then could you please share more information regarding this requirement. It will be helpful to validate and provide a better solution. 

Regards, 
Rahul 



JE Jeremy September 3, 2020 11:11 PM UTC

HI Rahul,

thanks for the reply.

Thanks for creating the feature request. I have over 10 years experience building enterprise applications using winforms and devexpress as the main UI toolsuite. Whilst I understand that web has differences, I was suggested to have a look at Syncfusion by a friend and ultimately I will still be comparing the ease of implementation and functionality of Syncfusion against the DevExpress suite of controls - whilst trying to learn Blazor and web development all at the same time.

Thanks for the information about the custom adapter - I havent had a chance to implement your suggestion yet, but having a quick look it seems to be what I am after, and just replying to say thankyou for the response.

Once I have had a chance to implement your suggestion I will let you know how it went.

Thanks,
Jeremy


RN Rahul Narayanasamy Syncfusion Team September 4, 2020 04:55 AM UTC

Hi Jeremy, 

Thanks for the update. 

Please get back to us if you need further assistance. 

Regards, 
Rahul 


Loader.
Up arrow icon