Completed
Last Updated: 09 Mar 2021 07:13 by ADMIN
Release 2.23.0
Matilda
Created on: 27 Dec 2019 13:53
Category: Grid
Type: Feature Request
24
Is there a way to implement custom validation in a blazor telerik grid when pressing Save/Update command button? If not, is there plans on providing custom validation as a feature in the near future?
2 comments
ADMIN
Marin Bratanov
Posted on: 15 Jul 2020 12:40

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

ADMIN
Marin Bratanov
Posted on: 28 Dec 2019 16:33

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

 UI for Blazor