-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added new kb article treelist-enable-checkbox-selection-only-edit-mode (
#2217) * Added new kb article treelist-enable-checkbox-selection-only-edit-mode * chore(treelist): update links and sample * Update knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md Co-authored-by: Yordan <60105689+yordan-mitev@users.noreply.github.com> * Update knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> * Update knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> * Update knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> * Update knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> * chore(reelist): address feedback --------- Co-authored-by: KB Bot <kb-bot@telerik.com> Co-authored-by: Nadezhda Tacheva <Nadezhda.Tacheva@progress.com> Co-authored-by: Nadezhda Tacheva <73842592+ntacheva@users.noreply.github.com> Co-authored-by: Yordan <60105689+yordan-mitev@users.noreply.github.com> Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com>
- Loading branch information
1 parent
179acb7
commit e392000
Showing
1 changed file
with
368 additions
and
0 deletions.
There are no files selected for viewing
368 changes: 368 additions & 0 deletions
368
knowledge-base/treelist-enable-checkbox-selection-only-edit-mode.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,368 @@ | ||
--- | ||
title: Enable TreeList Checkbox Selection Only in Edit Mode | ||
description: Learn how to show the Checkbox Column in the Telerik Blazor TreeList only in edit mode and hide it in display mode. | ||
type: how-to | ||
page_title: How to Enable Checkbox Selection Only in Edit Mode in Blazor TreeList | ||
slug: treelist-kb-enable-checkbox-selection-only-edit-mode | ||
tags: treelist, blazor, checkbox, selection, edit mode, visibility, checkboxcolumn | ||
res_type: kb | ||
ticketid: 1657252 | ||
--- | ||
|
||
## Environment | ||
|
||
<table> | ||
<tbody> | ||
<tr> | ||
<td>Product</td> | ||
<td>TreeList for Blazor, <br/ > Grid for Blazor</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
## Description | ||
|
||
This KB article answers the following questions: | ||
- How to disable the Checkbox selection in display mode and allow the user to select items only when editing? | ||
- How can I toggle the visibility of the Checkbox Column in the Blazor TreeList? | ||
- Is it possible to enable Checkbox selection only during edit mode in TreeList? | ||
- Can I hide the TreeList Checkbox Column in display mode and only show it in the edit mode? | ||
|
||
## Solution | ||
|
||
This article suggests two options to disable the TreeList Checkbox selection in display mode and enable it only in edit mode: | ||
|
||
* [Solution 1: Toggle the visibility of the CheckboxColumn](#solution-1-toggle-the-visibility-of-the-checkboxcolumn) | ||
* [Solution 2: Disable the CheckboxColumn with CSS](#solution-2-disable-the-checkboxcolumn-with-css) | ||
|
||
|
||
|
||
### Solution 1: Toggle the visibility of the CheckboxColumn | ||
|
||
1. Enable the [`CheckBoxOnlySelection` parameter]({%slug treelist-columns-checkbox%}#parameters) of the `TreeListCheckboxColumn` to prevent users from selecting rows with a click outside of edit mode. | ||
2. Bind the [`Visible` parameter]({%slug treelist-columns-checkbox%}#parameters) of the `TreeListCheckboxColumn` to a variable. This allows toggling its visibility based on whether the TreeList is in edit mode. | ||
3. Handle the CUD (Create, Update, Delete) events to manage the visibility of the `TreeListCheckboxColumn`. | ||
- For [`Inline`]({%slug treelist-editing-inline%}) and [`Popup`]({%slug treelist-editing-popup%}) edit modes, this approach works directly. In the [`Incell` edit mode the events flow is a bit different]({%slug treelist-editing-incell%}), so you may need to adjust the logic. | ||
|
||
Below is an example implementation that toggles the visibility of the Checkbox Column: | ||
|
||
```CSHTML | ||
<TelerikTreeList Data="@Data" | ||
ItemsField="@(nameof(Employee.DirectReports))" | ||
EditMode="@TreeListEditMode.Inline" | ||
OnUpdate="@UpdateItem" | ||
OnDelete="@DeleteItem" | ||
OnAdd="@AddItem" | ||
OnCreate="@CreateItem" | ||
OnEdit="@OnEditHandler" | ||
OnCancel="@OnCancelHandler" | ||
SelectionMode="@TreeListSelectionMode.Multiple" | ||
@bind-SelectedItems="SelectedItems" | ||
Pageable="true"> | ||
<TreeListToolBarTemplate> | ||
<TreeListCommandButton Command="Add" Icon="@SvgIcon.Plus">Add</TreeListCommandButton> | ||
</TreeListToolBarTemplate> | ||
<TreeListColumns> | ||
<TreeListCheckboxColumn Visible="@SelectionEnabled" CheckBoxOnlySelection="true" /> | ||
<TreeListColumn Field="Name" Expandable="true" Width="320px" /> | ||
<TreeListColumn Field="Id" Editable="false" Width="120px" /> | ||
<TreeListColumn Field="EmailAddress" Width="220px" /> | ||
<TreeListColumn Field="HireDate" Width="220px" /> | ||
<TreeListCommandColumn Width="280px"> | ||
<TreeListCommandButton Command="Add" Icon="@SvgIcon.Plus">Add Child</TreeListCommandButton> | ||
<TreeListCommandButton Command="Edit" Icon="@SvgIcon.Pencil">Edit</TreeListCommandButton> | ||
<TreeListCommandButton Command="Delete" Icon="@SvgIcon.Trash">Delete</TreeListCommandButton> | ||
<TreeListCommandButton Command="Save" Icon="@SvgIcon.Save" ShowInEdit="true">Update</TreeListCommandButton> | ||
<TreeListCommandButton Command="Cancel" Icon="@SvgIcon.Cancel" ShowInEdit="true">Cancel</TreeListCommandButton> | ||
</TreeListCommandColumn> | ||
</TreeListColumns> | ||
</TelerikTreeList> | ||
@code { | ||
private List<Employee> Data { get; set; } | ||
private IEnumerable<Employee> SelectedItems { get; set; } = new List<Employee>(); | ||
private bool SelectionEnabled { get; set; } | ||
private bool ItemAlreadySelected { get; set; } | ||
#region CUD operations | ||
private async Task UpdateItem(TreeListCommandEventArgs args) | ||
{ | ||
var item = args.Item as Employee; | ||
await MyService.Update(item); | ||
await GetTreeListData(); | ||
//Hide CheckboxColumn | ||
SelectionEnabled = false; | ||
} | ||
private async Task CreateItem(TreeListCommandEventArgs args) | ||
{ | ||
var item = args.Item as Employee; | ||
var parentItem = args.ParentItem as Employee; | ||
await MyService.Create(item, parentItem); | ||
await GetTreeListData(); | ||
//Hide CheckboxColumn | ||
SelectionEnabled = false; | ||
} | ||
private async Task DeleteItem(TreeListCommandEventArgs args) | ||
{ | ||
var item = args.Item as Employee; | ||
await MyService.Delete(item); | ||
await GetTreeListData(); | ||
} | ||
private async Task OnEditHandler(TreeListCommandEventArgs args) | ||
{ | ||
//Show CheckboxColumn | ||
SelectionEnabled = true; | ||
Employee empl = args.Item as Employee; | ||
//Check if the item is already selected, so you do not clear its selection in the OnCancel | ||
if (SelectedItems.Any(x => x.Id == empl.Id)) | ||
{ | ||
ItemAlreadySelected = true; | ||
} | ||
else | ||
{ | ||
ItemAlreadySelected = false; | ||
} | ||
} | ||
private async Task AddItem(TreeListCommandEventArgs args) | ||
{ | ||
//Show CheckboxColumn | ||
SelectionEnabled = true; | ||
} | ||
private async Task OnCancelHandler(TreeListCommandEventArgs args) | ||
{ | ||
Employee empl = args.Item as Employee; | ||
//Check if the user selected the item during the last edit and cancel it. Leave the selection if the item was previously selected | ||
if (!ItemAlreadySelected && SelectedItems.Any(x => x.Id == empl.Id)) | ||
{ | ||
SelectedItems = SelectedItems.Where(x => x.Id != empl.Id); | ||
} | ||
//Hide CheckboxColumn | ||
SelectionEnabled = false; | ||
} | ||
#endregion CUD operations | ||
#region Model | ||
public class Employee | ||
{ | ||
public int Id { get; set; } | ||
public string Name { get; set; } | ||
public string EmailAddress { get; set; } | ||
public DateTime HireDate { get; set; } | ||
public List<Employee> DirectReports { get; set; } | ||
public bool HasChildren { get; set; } | ||
// Used for the editing so replacing the object in the view-model data | ||
// will treat it as the same object and keep its state - otherwise it will | ||
// collapse after editing is done, which is not what the user would expect | ||
public override bool Equals(object obj) | ||
{ | ||
if (obj is Employee) | ||
{ | ||
return this.Id == (obj as Employee).Id; | ||
} | ||
return false; | ||
} | ||
} | ||
#endregion Model | ||
#region Data generation | ||
private async Task GetTreeListData() | ||
{ | ||
Data = await MyService.Read(); | ||
} | ||
protected override async Task OnInitializedAsync() | ||
{ | ||
await GetTreeListData(); | ||
} | ||
public static class MyService | ||
{ | ||
private static List<Employee> _data { get; set; } = new List<Employee>(); | ||
private static int LastId { get; set; } = 1; | ||
public static async Task Create(Employee itemToInsert, Employee parentItem) | ||
{ | ||
InsertItemRecursive(_data, itemToInsert, parentItem); | ||
} | ||
public static async Task<List<Employee>> Read() | ||
{ | ||
if (_data.Count < 1) | ||
{ | ||
for (int i = 1; i < 15; i++) | ||
{ | ||
Employee root = new Employee | ||
{ | ||
Id = LastId, | ||
Name = $"root: {i}", | ||
EmailAddress = $"{i}@example.com", | ||
HireDate = DateTime.Now.AddYears(-i), | ||
DirectReports = new List<Employee>(), | ||
HasChildren = true | ||
}; | ||
_data.Add(root); | ||
LastId++; | ||
for (int j = 1; j < 4; j++) | ||
{ | ||
int currId = LastId; | ||
Employee firstLevelChild = new Employee | ||
{ | ||
Id = currId, | ||
Name = $"first level child {j} of {i}", | ||
EmailAddress = $"{currId}@example.com", | ||
HireDate = DateTime.Now.AddDays(-currId), | ||
DirectReports = new List<Employee>(), | ||
HasChildren = true | ||
}; | ||
root.DirectReports.Add(firstLevelChild); | ||
LastId++; | ||
for (int k = 1; k < 3; k++) | ||
{ | ||
int nestedId = LastId; | ||
firstLevelChild.DirectReports.Add(new Employee | ||
{ | ||
Id = LastId, | ||
Name = $"second level child {k} of {j} and {i}", | ||
EmailAddress = $"{nestedId}@example.com", | ||
HireDate = DateTime.Now.AddMinutes(-nestedId) | ||
}); ; | ||
LastId++; | ||
} | ||
} | ||
} | ||
_data[0].Name += " (non-editable, see OnEdit)"; | ||
} | ||
return await Task.FromResult(_data); | ||
} | ||
public static async Task Update(Employee itemToUpdate) | ||
{ | ||
UpdateItemRecursive(_data, itemToUpdate); | ||
} | ||
public static async Task Delete(Employee itemToDelete) | ||
{ | ||
RemoveChildRecursive(_data, itemToDelete); | ||
} | ||
public static void UpdateItemRecursive(List<Employee> items, Employee itemToUpdate) | ||
{ | ||
for (int i = 0; i < items.Count; i++) | ||
{ | ||
if (items[i].Id.Equals(itemToUpdate.Id)) | ||
{ | ||
items[i] = itemToUpdate; | ||
return; | ||
} | ||
if (items[i].DirectReports?.Count > 0) | ||
{ | ||
UpdateItemRecursive(items[i].DirectReports, itemToUpdate); | ||
} | ||
} | ||
} | ||
public static void RemoveChildRecursive(List<Employee> items, Employee item) | ||
{ | ||
for (int i = 0; i < items.Count(); i++) | ||
{ | ||
if (item.Equals(items[i])) | ||
{ | ||
items.Remove(item); | ||
return; | ||
} | ||
else if (items[i].DirectReports?.Count > 0) | ||
{ | ||
RemoveChildRecursive(items[i].DirectReports, item); | ||
if (items[i].DirectReports.Count == 0) | ||
{ | ||
items[i].HasChildren = false; | ||
} | ||
} | ||
} | ||
} | ||
public static void InsertItemRecursive(List<Employee> Data, Employee insertedItem, Employee parentItem) | ||
{ | ||
insertedItem.Id = LastId++; | ||
if (parentItem != null) | ||
{ | ||
parentItem.HasChildren = true; | ||
if (parentItem.DirectReports == null) | ||
{ | ||
parentItem.DirectReports = new List<Employee>(); | ||
} | ||
parentItem.DirectReports.Insert(0, insertedItem); | ||
} | ||
else | ||
{ | ||
Data.Insert(0, insertedItem); | ||
} | ||
} | ||
} | ||
#endregion Data generation | ||
} | ||
``` | ||
|
||
### Solution 2: Disable the CheckboxColumn with CSS | ||
|
||
Alternatively, if you prefer not to toggle the `CheckboxColumn` visibility but just disable it, you can apply conditional custom CSS based on the flag that you set in the `OnEdit`/`OnAdd` handlers. | ||
|
||
````CSTHML | ||
@if (!SelectionEnabled) | ||
{ | ||
<style> | ||
.checkbox-in-edit-treelist .k-table-thead th:first-of-type input, | ||
.checkbox-in-edit-treelist .k-table-row td:first-of-type input { | ||
pointer-events:none !important; | ||
opacity: 0.6; | ||
} | ||
</style> | ||
} | ||
<TelerikTreeList Data="@Data" | ||
Class="checkbox-in-edit-treelist"> | ||
@* Your TreeList configuration here *@ | ||
</TelerikTreeList> | ||
```` | ||
|
||
## See Also | ||
|
||
- [TreeList Overview]({%slug treelist-overview%}) | ||
- [TreeList Editing]({%slug treelist-editing-overview%}) | ||
- [TreeList Selection]({%slug treelist-selection-overview%}) |