Like this (example taken from "https://demos.telerik.com/aspnet-mvc/grid/editing-custom-validation"):
Here is a sample of putting an edit form in the editor template of a particular cell in incell editing. Note that as the models become more complex, this will need to adapt (e.g., use another editor depending on the type of the field).
@using System.ComponentModel.DataAnnotations
<TelerikGrid Data=@MyData EditMode="@GridEditMode.Incell" Pageable="true" Height="500px" @ref="@Grid"
OnUpdate="@UpdateHandler" OnDelete="@DeleteHandler" OnCreate="@CreateHandler">
<GridToolBar>
<GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton>
</GridToolBar>
<GridColumns>
<GridColumn Field=@nameof(SampleData.ID) Title="ID" Editable="false" />
<GridColumn Field=@nameof(SampleData.Name) Title="Name">
<EditorTemplate Context="currModel">
@* see why naming context variables is needed here https://docs.telerik.com/blazor-ui/knowledge-base/nest-render-fragment
you may, of course, choose to name a different context - like the one of the form*@
@{
if (currRow == null || currEditContext == null)
{ // populate these objects only once per render, otherwise you won't be able to type into the inputs due to the re-renders renewing the model and context
currRow = currModel as SampleData;
currEditContext = new EditContext(currModel);
}
// see the notes here on closing a custom editor
// https://docs.telerik.com/blazor-ui/components/grid/editing/incell#notes
<EditForm EditContext="@currEditContext">
@* a form needs a model *@
<DataAnnotationsValidator /> @* make sure to have a validator *@
<InputText @bind-Value="@currRow.Name" @onblur="@( () => TryCloseEditor("Name") )"></InputText>
<ValidationMessage For="@(() => currRow.Name)" />
</EditForm>
}
</EditorTemplate>
</GridColumn>
<GridCommandColumn>
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
<GridCommandButton Command="Delete" Icon="delete">Delete</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
@code {
public TelerikGrid<SampleData> Grid { get; set; }
SampleData currRow { get; set; }
EditContext currEditContext { get; set; }
async Task TryCloseEditor(string fieldName)
{
// we use the edit context to check for validation errors for a specific field
var valMessages = currEditContext.GetValidationMessages(new FieldIdentifier(currRow, fieldName));
if (valMessages.Count() != 0)
{
return;
}
var state = Grid?.GetState();
if (currRow.ID == 0 && state.InsertedItem != null)
{
// insert operation - the item is new
await CreateHandler(new GridCommandEventArgs()
{
Item = state.InsertedItem
});
}
else
if (currRow.ID > 0 && state.EditItem != null)
{
// edit operation on an existing item
await UpdateHandler(new GridCommandEventArgs()
{
Item = state.EditItem,
Field = state.EditField
});
}
state.InsertedItem = state.OriginalEditItem = state.EditItem = default;
// clean up the variables used for the edit form so they can be instantiated properly the next time a cell is edited
currRow = null;
currEditContext = null;
await Task.Delay(20); // let the grid re-render and close the cell if keyboard navigation is enabled
await Grid?.SetState(state);
}
async Task UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
var index = MyData.FindIndex(i => i.ID == item.ID);
if (index != -1)
{
MyData[index] = item;
// this copies the entire item, consider altering only the needed field
}
}
async Task CreateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
item.ID = MyData.Count + 1;
MyData.Insert(0, item);
}
async Task DeleteHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
MyData.Remove(item);
}
// in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public class SampleData
{
public int ID { get; set; }
[Required]
[StringLength(10, ErrorMessage = "That name is too long")]
public string Name { get; set; }
}
public List<SampleData> MyData { get; set; }
protected override void OnInitialized()
{
MyData = new List<SampleData>();
for (int i = 0; i < 50; i++)
{
MyData.Add(new SampleData()
{
ID = i,
Name = "Name " + i.ToString()
});
}
}
}
Regards,
Marin Bratanov
Progress Telerik
Hi Matilda,
The PopUp editing of the grid already provides validation, you can see it in action in our demos: https://demos.telerik.com/blazor-ui/grid/editing-popup.
With the inline editing, that would be tougher - in Blazor, validation requires an EditForm component and both the validated input and the button that triggers the submission must be inside that form. That can't happen with separate cells because we need to keep the HTML valid. The alternative of having a form, validator, validation summary and a hidden button for each cell would weigh everything down and would not perform well.
The only option for an inline editing form to have validation would be some sort of a custom edit form template that you'd have to define yourself (something similar to this: https://demos.telerik.com/aspnet-ajax/grid/examples/data-editing/form-template-update/defaultcs.aspx).
You can also have that custom edit form outside of the grid right now, and you can have validation there too, here are examples:
All that being said, I would appreciate your feedback on how that would work for you, and mostly whether you would like to see such a custom edit form feature added to the Blazor grid, because that would be the only way to have validation and something similar to Inline editing.
Regards,
Marin Bratanov
Progress Telerik