Unplanned
Last Updated: 04 Nov 2020 10:48 by ADMIN
Miriam
Created on: 04 Nov 2020 10:48
Category: Grid
Type: Feature Request
2
Ability to prevent multiple calls of async UpdateHandler when pressing enter in InCell edit mode

https://docs.telerik.com/blazor-ui/components/grid/editing/incell#notes 

I am using an EditorTemplate with a method called ChangeHandler(). After clicking in another row everything works fine but if I leave the cell by pressing enter the UpdateHandler gets called more than two times and comparing args.Item with the GridItem doesn't help because the calls are asynchronous.

=====

Admin Edit

After discussion with the development team, the proposed resolution is to provide a context that provides Save/Cancel operations. The goal is to provide easier configuration for IncellEditing and EditorTemplates and consistent behavior with mouse and keyboard interaction. However, the change will introduce a breaking change in our EditorTemplate, should be researched further and that is why this is logged as a feature request. A small snippet how providing the context will change the setup:

<EditorTemplate>
         <TelerikTextBox @bind-Value=@context.Item.Name OnChange="@(() => context.Save())" Width="100%" />
</EditorTemplate>

Workaround

<TelerikGrid @ref="@Grid"
             Data=@MyData
             EditMode="@GridEditMode.Incell"
             Pageable="true"
             Height="500px"
             OnUpdate="@UpdateHandler" 
             Navigable="true">
    <GridColumns>
        <GridColumn Field=@nameof(SampleData.ID) Editable="false" Title="ID" />
        <GridColumn Field=@nameof(SampleData.Name) Title="Name">
            <EditorTemplate>
                @{
                    currentItem = context as SampleData;
                    <span @onkeydown="@OnKeyDown">
                        <TelerikTextBox @bind-Value=@currentItem.Name OnChange="@CloseEditor" Width="100%" />
                    </span>
                }
            </EditorTemplate>
        </GridColumn>
        <GridColumn Field=@nameof(SampleData.Ranking) Title="Ranking" Width="120px">
            <EditorTemplate>
                @{
                    currentItem = context as SampleData;
                    <TelerikNumericTextBox @bind-Value=@currentItem.Ranking OnChange="@CloseEditor"
                                           Width="100%" Max="10" Min="0" Step="1">
                    </TelerikNumericTextBox>
                }
            </EditorTemplate>
        </GridColumn>
        <GridColumn Field=@nameof(SampleData.Role) Title="Position" Width="200px">
            <EditorTemplate>
                @{
                    currentItem = context as SampleData;
                    <TelerikDropDownList Data="@Roles" @bind-Value="@currentItem.Role" OnChange="@CloseEditor"
                                         Width="120px" PopupHeight="auto">
                    </TelerikDropDownList>
                }
            </EditorTemplate>
        </GridColumn>
        <GridCommandColumn>
            <GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Save</GridCommandButton>
        </GridCommandColumn>
    </GridColumns>
    <GridToolBar>
        <GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton>
    </GridToolBar>
</TelerikGrid>

@code {
    // handling the custom editor template for InCell editing
    public TelerikGrid<SampleData> Grid { get; set; }
    public SampleData currentItem { get; set; }
    public bool ShouldUpdateItem { get; set; }

    public void OnKeyDown(KeyboardEventArgs args)
    {
        if (args.Key == "Enter")
        {
            ShouldUpdateItem = false;
        }
    }

    async Task CloseEditor()
    {
        var state = Grid?.GetState();

        if (currentItem.ID == 0 && state.InsertedItem != null)
        {
            // insert operation - the item is new
            await CreateHandler(new GridCommandEventArgs()
            {
                Item = state.InsertedItem
            });
        }
        else
        if (currentItem.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;

        await Task.Delay(20); // let the grid re-render and close the cell if keyboard navigation is enabled

        await Grid?.SetState(state);
    }

    //Create and Update operations

    async Task UpdateHandler(GridCommandEventArgs args)
    {
        SampleData item = (SampleData)args.Item;

        if (ShouldUpdateItem == false)
        {
            ShouldUpdateItem = true;
            return;
        }

        var index = MyData.FindIndex(i => i.ID == item.ID);
        if (index != -1)
        {
            // with keyboard navigation and Enter key press in the component
            // both the grid, and the OnChange handler will raise the update event
            // you may want to add an equality comparison for the item to only call the database once
            // when the item has changed, not both times
            if (!MyData[index].Equals(item))
            {
                MyData[index] = item;
                Console.WriteLine("update");
                //perform actual data source operations here
            }
        }
    }


    // data sources

    protected override void OnInitialized()
    {
        MyData = new List<SampleData>();

        for (int i = 1; i < 50; i++)
        {
            MyData.Add(new SampleData()
            {
                ID = i,
                Name = "name " + i,
                Ranking = i % 10
            });
        }
    }

    public class SampleData
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Role { get; set; }
        public int Ranking { get; set; }

        public override bool Equals(object obj)
        {
            if (obj != null && obj is SampleData)
            {
                SampleData curr = obj as SampleData;
                return (ID == curr.ID) && (Name == curr.Name) && (Role == curr.Role) && (Ranking == curr.Ranking);
            }
            return false;
        }
    }

    List<SampleData> MyData { get; set; }
    static List<string> Roles = new List<string> { "Manager", "Employee", "Contractor" };
}

=====

0 comments