Completed
Last Updated: 19 May 2021 06:59 by ADMIN
Release 2.25.0
Christian
Created on: 09 Apr 2020 16:52
Category: Grid
Type: Feature Request
64
Pass the model context to command button

I would like to be able to do something like

<GridCommandColumn>
@{
context as MyModel;
if(context.ShowButton)
{
<GridCommandButton>Todo</GridCommandButton>
}
}
</GridCommandColumn>

 

---

ADMIN EDIT

See the thread below for a way to implement this right now with your own buttons in a "regular" column and the grid state.

---

6 comments
ADMIN
Marin Bratanov
Posted on: 09 Dec 2020 11:44

Hi Denis,

You can prevent the click event from propagating to other elements by wrapping the button in a span that does this, here's an example based on the RowClick event article where I added such a button:

@* Use the OnRowClick event to load data on demand based on the clicked row *@

There is a deliberate delay in the data loading to showcase the async nature of the event

<TelerikGrid Data="@MyData"
             Height="400px"
             Width="700px"
             Pageable="true"
             OnRowClick="@OnRowClickHandler"
             SelectionMode="@GridSelectionMode.Single"
             @bind-SelectedItems="@SelectedItems">
    <GridColumns>
        <GridColumn Field="@(nameof(SampleData.Id))" Width="120px" />
        <GridColumn Field="@(nameof(SampleData.Name))" Title="Employee Name" />
        <GridColumn Field="@(nameof(SampleData.Team))" Title="Team" />
        <GridColumn Field="@(nameof(SampleData.HireDate))" Title="Hire Date" />
        <GridColumn Title="no row click on this button">
            <Template>
                <span @onclick:preventDefault="true" @onclick:stopPropagation="true">
                    <TelerikButton OnClick="@MyButtonClick">Some button</TelerikButton>
                </span>
            </Template>
        </GridColumn>
    </GridColumns>
</TelerikGrid>

@if (ProjectData.Any())
{
    <br />
    <TelerikGrid Data="@ProjectData" AutoGenerateColumns="true"
                 Pageable="true" PageSize="4" Width="700px">
    </TelerikGrid>
}

@code {
    void MyButtonClick()
    {
        // in reality this would probably be called by a lambda so you can also pass the current row model
        Console.WriteLine("button click");
    }

    public IEnumerable<SampleData> SelectedItems { get; set; } = Enumerable.Empty<SampleData>();

    public List<ProjectModel> ProjectData { get; set; } = new List<ProjectModel>();

    async Task OnRowClickHandler(GridRowClickEventArgs args)
    {
        var model = args.Item as SampleData;

        ProjectData = await GetProjectData(model.Id);

        if (args.EventArgs is KeyboardEventArgs keyboardEventArgs)
        {
            Console.WriteLine($"The user clicked {keyboardEventArgs.Key} on row {model.Name}");
        }
        else if (args.EventArgs is MouseEventArgs mouseEventArgs)
        {
            Console.WriteLine($"The user clicked {mouseEventArgs.ClientX} {mouseEventArgs.ClientY} on row {model.Name}");
        }
    }

    async Task<List<ProjectModel>> GetProjectData(int id)
    {
        await Task.Delay(500); // simulate loading data from a service, remove from a real app

        ProjectData = new List<ProjectModel>()
    {
            new ProjectModel()
            {
                ProjectManagerId = id,
                ProjectName = $"Project name {id}",
                DueDate = DateTime.Today.AddDays(-id),
                isActive = id % 2 == 0 ? true : false
            }
        };
        return await Task.FromResult(ProjectData);
    }

    public IEnumerable<SampleData> MyData = Enumerable.Range(1, 30).Select(x => new SampleData
    {
        Id = x,
        Name = "name " + x,
        Team = "team " + x % 5,
        HireDate = DateTime.Now.AddDays(-x).Date
    });

    public class SampleData
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Team { get; set; }
        public DateTime HireDate { get; set; }
    }

    public class ProjectModel
    {
        public int ProjectManagerId { get; set; }
        public string ProjectName { get; set; }
        public DateTime DueDate { get; set; }
        public bool isActive { get; set; }
    }
}

 

Regards,
Marin Bratanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Denis
Posted on: 09 Dec 2020 09:03

Hi,

I stumbled about the same problem, but for me, the suggestion to use a standard column with normal buttons is not a solution. I also want to act on the selection of rows (OnRowClick event) and this collides with the button in the cell. I cannot press the button without having my OnRowClick event fired instead of the button click handler.

@Marin,Svetoslav: Is there any workaround for that situation?

George
Posted on: 04 Nov 2020 20:30

I just need the context in the GridCommandColumn and I can do the rest.

 

I need to look at a field so I can not show the buttons for certain fields.

Christian
Posted on: 02 Jun 2020 10:24

Hello Marin, hello Svetoslav,

thank you for the detailed information. This was exactly the thing I was searching for.

Therefore, I'm not sure if we still need the context in the command button (At least not from my side). Others might be still interested in the feature, however :)

 

Best regards,

Christian

ADMIN
Svetoslav Dimitrov
Posted on: 28 May 2020 13:37

Hello,

A runnable example on how to create a custom GridCommandColumn, in order to use the context, you can see from the sample below:

@using System.Collections.ObjectModel;

<TelerikGrid Data=@MyData
             EditMode="@GridEditMode.Inline"
             Pageable="true"
             Height="400px"
             @ref="GridRef"
             Navigable="true">
    <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" />
        <GridColumn>
            <Template>
                @{
                    var item = context as SampleData;
                    <TelerikButton Icon="@IconName.Edit" OnClick="@(() => UpdateHandler(item))">Edit</TelerikButton>
                    <TelerikButton Icon="@IconName.Delete" OnClick="@(() => DeleteHandler(item))">Delete</TelerikButton>
                    if (item.Name != $"Name 2")
                    {
                        <TelerikButton Icon="@IconName.Information" OnClick="@(() => Result = $"More information on {item.Name}")">Information</TelerikButton>
                    }
                }
            </Template>
            <EditorTemplate>
                @{
                    var item = context as SampleData;
                    <TelerikButton Icon="@IconName.Save" OnClick="@(() => SaveItem(item) )">Save</TelerikButton>
                }
            </EditorTemplate>
        </GridColumn>
    </GridColumns>
</TelerikGrid>

<br />

@Result

@code {
    public string Result { get; set; }
    public bool inEdit { get; set; }
    public TelerikGrid<SampleData> GridRef { get; set; }
    public ObservableCollection<SampleData> MyData { get; set; }

    async Task UpdateHandler(SampleData item)
    {
        inEdit = true;
        var currentState = GridRef.GetState();

        SampleData itemToEdit = SampleData.GetClonedInstance(MyData.Where(x => x.ID == item.ID).FirstOrDefault());
        itemToEdit.Name = "Edited from method";
        currentState.OriginalEditItem = itemToEdit;
        currentState.EditItem = null;
        await GridRef.SetState(currentState);
    }

    async Task DeleteHandler(SampleData item)
    {
        MyData.Remove(item);
    }

    async Task SaveItem(SampleData item)
    {
        var currentState = GridRef.GetState();

        int indexOfOriginalitem = MyData.IndexOf(currentState.OriginalEditItem);

        currentState.OriginalEditItem = default;
        currentState.EditItem = default;

        MyData[indexOfOriginalitem] = item;

        await GridRef.SetState(currentState);
    }


    // 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; }
        public string Name { get; set; }

        public SampleData()
        {

        }

        public SampleData(SampleData itmToClone)
        {
            this.ID = itmToClone.ID;
            this.Name = itmToClone.Name;
        }

        public static SampleData GetClonedInstance(SampleData itmToClone)
        {
            return new SampleData(itmToClone);
        }

        public override bool Equals(object obj)
        {
            if (obj is SampleData)
            {
                return this.ID == (obj as SampleData).ID;
            }
            return false;
        }
    }


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

        for (int i = 0; i < 50; i++)
        {
            MyData.Add(new SampleData()
            {
                ID = i,
                Name = "Name " + i.ToString()
            });
        }
    }
}

Regards,
Svetoslav Dimitrov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
ADMIN
Marin Bratanov
Posted on: 09 Apr 2020 16:55

Hello Christian,

We would like to do that, but it will require a breaking change in the structure of the command column.

For the time being you can use a "regular" column without a field and add in its Template "regular" buttons that control the grid state programmatically (e.g., add the current item as an edited item), as shown here: https://docs.telerik.com/blazor-ui/components/grid/state#initiate-editing-or-inserting-of-an-item

 

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.