I have been working with the Blazor Grid and Hierachal edits. I am able to display the hierarch without an issue.
For the parent record, the CRUD operations work. For the child record, I am getting the following error when I use ADD or EDIT. I was suspecting a Primary Key issue, but that does not seem to be by case. I am hoping you can provide a few insights on this error.
Thanks for any information you can provide on this. Marc.
Uncaught (in promise) Error: System.InvalidOperationException: Unable to create EditContext from type serverAuthTest.shared.Def.VUserRole, handle object creation or give EditContext using OnActionBegin event. For batch editing use OnBatchAdd and OnCellEdit events to provide new item.
at Syncfusion.Blazor.Grids.Internal.Edit`1.EnsureDataAndEditContext(Object& data, ActionEventArgs`1 actionArgs, BeforeBatchAddArgs`1 batchAddArgs, CellEditArgs`1 cellEditArgs)
at Syncfusion.Blazor.Grids.Internal.Edit`1.AddRecord(Object data, Nullable`1 index)
at Syncfusion.Blazor.Grids.SfGrid`1.AddRecord()
at Syncfusion.Blazor.Grids.Internal.GridToolbar`1.ToolbarClickHandler(ClickEventArgs args)
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Syncfusion.Blazor.Navigations.SfToolbar.TriggerClickEvent(MouseEventArgs e, Boolean isPopupElement, Boolean isCloseIcon, Nullable`1 trgParentDataIndex, String id, Nullable`1 tabItemIndex)
at Tt.endInvokeDotNetFromJS (blazor.server.js:1)
at blazor.server.js:1
at Array.forEach (<anonymous>)
at Tt._invokeClientMethod (blazor.server.js:1)
at Tt._processIncomingData (blazor.server.js:1)
at bt.Tt.connection.onreceive (blazor.server.js:1)
at WebSocket.o.onmessage (blazor.server.js:1)
endInvokeDotNetFromJS @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
_invokeClientMethod @ blazor.server.js:1
_processIncomingData @ blazor.server.js:1
Tt.connection.onreceive @ blazor.server.js:1
o.onmessage @ blazor.server.js:1
The HTML for the child portion of the Grid is as follows:
@*Child table *@
<GridTemplates>
<DetailTemplate>
@{
var vHdr = (context as User);
var parentPK = vHdr.Id;
<SfGrid DataSource="@AllUserRoles"
AllowResizing="true"
Query="@(new Query().Where("UserId", "equal", vHdr.Id))"
Toolbar="@(new List<string>() { "Add","Edit", "Delete", "Update", "Cancel" })">
<GridEditSettings AllowAdding="true"
AllowDeleting="true"
AllowEditing="true"
ShowDeleteConfirmDialog="true"
Mode="EditMode.Normal"/>
@*GridEvents OnActionBegin="ActionBeginHandlerChild" OnActionComplete="ActionCompleteHandlerChild" TValue="FieldAlias"></GridEvents> *@
@*child table col headings*@
<GridColumns>
<GridColumn Field=@nameof(VUserRole.RoleId) HeaderText="Role ID" TextAlign="TextAlign.Left" LockColumn="true" AllowAdding="true" Width="2"> </GridColumn>
<GridColumn Field=@nameof(VUserRole.UserId) HeaderText="UserID" Width="3" TextAlign="TextAlign.Left" />
<GridColumn Field=@nameof(VUserRole.RoleUser) HeaderText="RoleUser" Width="4" TextAlign="TextAlign.Left" IsPrimaryKey="true" LockColumn="false" AllowAdding="true" />
</GridColumns>
</SfGrid>
}
</DetailTemplate>
</GridTemplates>
The class used for @AllUserRoles is:
namespace serverAuthTest.shared.Def
{
public class VUserRole
{
public VUserRole() { }
public VUserRole(string roleid, string userid, string roleuser)
{
RoleId = roleid;
UserId = userid;
RoleUser = roleuser;
}
public string RoleId { get; set; }
public string UserId { get; set; }
[Key]
public string RoleUser { get; set; }
}
}
|
<SfGrid DataSource="@Orders" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" })">
<GridEditSettings AllowEditing="true" AllowAdding="true" AllowDeleting="true" Mode="EditMode.Dialog"></GridEditSettings>
<GridColumns>
. . .
</GridColumns>
<GridEvents TValue="Order" OnActionBegin="ActionBegin"></GridEvents>
</SfGrid>
@code {
. . .
public void ActionBegin(ActionEventArgs<Order> arg)
{
//Handles add operation
if (arg.RequestType.Equals(Syncfusion.Blazor.Grids.Action.Add))
{
arg.Data = new Order(0) { CustomerID = "Customer ID" };
}
//Handles edit operation. During edit operation, original object will be cloned.
if (arg.RequestType.Equals(Syncfusion.Blazor.Grids.Action.BeginEdit))
{
arg.Data = new Order(arg.RowData.OrderID)
{
CustomerID = arg.RowData.CustomerID,
Freight = arg.RowData.Freight,
OrderDate = arg.RowData.OrderDate
};
}
}
// This class does not contain any parameter-less constructor, hence this cannot be instantiated using Activator.CreateInstance.
public class Order
{
public Order(int? orderid) => OrderID = orderid;
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
} |
Thanks.
Your suggestion worked, but I do not understand why. If you look at the original thread
In the link you provided, it states the following - namely I should not need the onAction begin event . For the VUserRole class, I defined a parameterless constructor. Should this be enough not to require explicitly declaring it?
Grid uses Activator.CreateInstance<TValue>() to create or clone new record instance during add and edit operations, so it is must to have parameterless constructor defined for the model class.
There are cases where custom logic is required for creating new object or new object instance cannot be created using Activator.CreateInstance<TValue>(). In such cases you can provide model object instance manually using events.
My next question is for the following block of code. If I put a debug stop event on the highlighted line, it does not seem to be hit. Thoughts.
public async Task ActionBeginHandlerChild(ActionEventArgs<VUserRole> Args)
{
if (Args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.Save))
{
if (Args.Action == "Add")
{
Args.Data = new VUserRole("r1", "u1", "r1u1");
//Args.Data = new VUserRole(0) { RoleId = "r1", UserId = "u1", RoleUser = "r1u1" };
//InjUserDataSvc.AddNew(Args.Data);
}
else
Thanks for your help.. I think I am good. Marc.