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.
---
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/.
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?
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.
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
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
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