Skip to content

Commit 7b9f4ac

Browse files
committed
polish KB article
1 parent e28ffa6 commit 7b9f4ac

File tree

1 file changed

+72
-41
lines changed

1 file changed

+72
-41
lines changed
Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
---
2-
title: Add and Remove Tabs
2+
title: Add and Remove TabStrip Tabs
33
description: Learn how to dynamically add and remove tabs
44
type: how-to
5-
page_title: Add and Remove Tabs
5+
page_title: How to Add and Remove TabStrip Tabs
66
slug: tabstrip-kb-add-remove-tabs
77
tags: telerik,blazor,tabstrip,add tabs,remove tabs
8-
ticketid:
8+
ticketid:
99
res_type: kb
10-
previous_url: /knowledge-base/tabstrip-dynamic-tabs
1110
---
1211

1312
## Environment
@@ -21,7 +20,6 @@ previous_url: /knowledge-base/tabstrip-dynamic-tabs
2120
</tbody>
2221
</table>
2322

24-
2523
## Description
2624

2725
I have a collection of items representing separate tabs. I am iterating through that collection to render a tab for each item as shown in the [Tabs Collection article](slug:tabstrip-tabs-collection). I want to allow the user to add and remove tabs. How to achieve that?
@@ -35,40 +33,43 @@ This KB article also answers the following questions:
3533

3634
## Solution
3735

38-
* Use a [`HeaderTemplate`](slug:tabstrip-header-template) for the tab to add an "X" button.
39-
* Display the "X" button only when there is more than one tab.
40-
* Declare a "+" button for adding tabs.
41-
* Use custom styling and JavaScript to position the "+" button next to the last tab header.
36+
1. [Render the TabStrip tabs in a loop](slug:tabstrip-tabs-collection).
37+
1. Use a [`HeaderTemplate`](slug:tabstrip-header-template) for the tabs to add Remove buttons. You can display the buttons conditionally based on the tab count.
38+
1. Declare a button for adding new tabs.
39+
1. Use custom styling and JavaScript to position the Add button next to the last tab header.
40+
41+
>caption Adding and removing TabStrip tabs at runtime
4242
4343
````RAZOR
4444
@inject IJSRuntime JS
4545
4646
<div class="dynamic-tabstrip-wrapper k-relative">
4747
<TelerikButton OnClick="@AddTab"
4848
Class="add-tab-button !k-absolute k-z-10 k-ratio-1"
49-
Icon="@SvgIcon.Plus"
5049
FillMode="@ThemeConstants.Button.FillMode.Flat"
51-
ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
52-
Rounded="@ThemeConstants.Button.Rounded.Full" />
50+
Icon="@SvgIcon.Plus"
51+
ThemeColor="@ThemeConstants.Button.ThemeColor.Primary" />
52+
5353
<TelerikTabStrip @bind-ActiveTabId="@ActiveTabId" PersistTabContent="true">
5454
@foreach (Tab tab in Tabs)
5555
{
5656
<TabStripTab @key="tab.Id" Id="@tab.Id">
5757
<HeaderTemplate>
5858
<div class="k-flex-layout k-gap-2">
59-
@tab.Title
59+
<span>@tab.Title</span>
6060
@if (Tabs.Count > 1)
6161
{
6262
<TelerikButton OnClick="@(() => RemoveTab(tab))"
6363
Class="remove-tab-button"
64-
Icon="@SvgIcon.X"
6564
FillMode="@ThemeConstants.Button.FillMode.Flat"
65+
Icon="@SvgIcon.X"
66+
Size="@ThemeConstants.Button.Size.Small"
6667
ThemeColor="@ThemeConstants.Button.ThemeColor.Primary" />
6768
}
6869
</div>
6970
</HeaderTemplate>
7071
<Content>
71-
Content for @tab.Title
72+
Content for <strong>@tab.Title</strong>
7273
</Content>
7374
</TabStripTab>
7475
}
@@ -95,45 +96,54 @@ This KB article also answers the following questions:
9596
}
9697
</style>
9798
99+
@* Move JavaScript code to a JS file *@
98100
<script suppress-error="BL9992">
99101
window.positionAddTabButton = () => {
100-
const tabStripItems = Array.from(document.querySelectorAll(".dynamic-tabstrip-wrapper .k-tabstrip-item"));
101-
const tabStripWrapperWidth = document.querySelector(".dynamic-tabstrip-wrapper").scrollWidth;
102+
const tabStripItems = Array.from(document.querySelectorAll(".dynamic-tabstrip-wrapper .k-tabstrip-item"));
103+
const tabStripWrapperWidth = document.querySelector(".dynamic-tabstrip-wrapper").scrollWidth;
102104
103-
let totalWidth = !tabStripItems ? 0 : tabStripItems.reduce(
104-
(accumulator, currentItem) => accumulator + parseFloat(currentItem.getBoundingClientRect().width),
105-
0,
106-
);
105+
let totalWidth = !tabStripItems ? 0 : tabStripItems.reduce(
106+
(accumulator, currentItem) => accumulator + parseFloat(currentItem.getBoundingClientRect().width),
107+
0,
108+
);
107109
108-
const addTabButton = document.querySelector(".add-tab-button");
109-
const addTabButtonWidth = addTabButton.getBoundingClientRect().width;
110+
const addTabButton = document.querySelector(".add-tab-button");
111+
const addTabButtonWidth = addTabButton.getBoundingClientRect().width;
110112
111-
// Assure button is never positioned outside the boundaries of the wrapper
112-
if (totalWidth + addTabButtonWidth > tabStripWrapperWidth) {
113-
totalWidth = tabStripWrapperWidth - addTabButtonWidth;
114-
}
113+
// assure button is never positioned outside the boundaries of the wrapper
114+
if (totalWidth + addTabButtonWidth > tabStripWrapperWidth) {
115+
totalWidth = tabStripWrapperWidth - addTabButtonWidth;
116+
}
115117
116-
addTabButton.style.left = `${totalWidth}px`;
118+
addTabButton.style.left = `${totalWidth}px`;
117119
};
118120
</script>
119121
120-
@code {
121-
private string ActiveTabId { get; set; } = string.Empty;
122122
123-
private List<Tab> Tabs = new List<Tab>
123+
@code {
124+
private List<Tab> Tabs = new List<Tab>()
124125
{
125-
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 1" },
126-
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 2" },
127-
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 3" }
126+
new Tab { Title = "Tab 1" },
127+
new Tab { Title = "Tab 2" },
128+
new Tab { Title = "Tab 3" }
128129
};
129130
131+
private string ActiveTabId { get; set; } = string.Empty;
132+
133+
private bool ShouldPositionAddButton { get; set; }
134+
135+
private int LastTabNumber { get; set; } = 3;
136+
130137
private void AddTab()
131138
{
132-
var tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = "New Tab" };
139+
Tab tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = $"New Tab {++LastTabNumber}" };
140+
133141
Tabs.Add(tabToAdd);
134142
135-
// Activate the newly added tab
143+
//In this example, we are always activating the newly added tab. Adjust the logic to activate a different tab if needed.
136144
ActiveTabId = tabToAdd.Id;
145+
146+
ShouldPositionAddButton = true;
137147
}
138148
139149
private void RemoveTab(Tab tab)
@@ -143,26 +153,47 @@ This KB article also answers the following questions:
143153
return;
144154
}
145155
156+
// Activate the tab after or before the removed one if it's active
157+
if (ActiveTabId == tab.Id)
158+
{
159+
int removedTabIndex = Tabs.FindIndex(x => x.Id == tab.Id);
160+
if (removedTabIndex == Tabs.Count - 1)
161+
{
162+
ActiveTabId = Tabs.ElementAt(removedTabIndex - 1).Id;
163+
}
164+
else
165+
{
166+
ActiveTabId = Tabs.ElementAt(removedTabIndex + 1).Id;
167+
}
168+
}
169+
146170
Tabs.Remove(tab);
147171
148-
// Activate the first tab after removal
149-
ActiveTabId = Tabs[0].Id;
172+
ShouldPositionAddButton = true;
150173
}
151174
152175
protected override async Task OnAfterRenderAsync(bool firstRender)
153176
{
154-
await JS.InvokeVoidAsync("positionAddTabButton");
177+
if (firstRender || ShouldPositionAddButton)
178+
{
179+
ShouldPositionAddButton = false;
180+
await JS.InvokeVoidAsync("positionAddTabButton");
181+
}
182+
155183
await base.OnAfterRenderAsync(firstRender);
156184
}
157185
158186
public class Tab
159187
{
160-
public string Id { get; set; } = string.Empty;
188+
public string Id { get; set; } = Guid.NewGuid().ToString();
189+
161190
public string Title { get; set; } = string.Empty;
162191
}
192+
163193
}
164194
````
165195

166196
## See Also
167197

168-
* [Dynamic Tabs](slug:tabstrip-tabs-collection)
198+
* [Dynamic Tab Collection](slug:tabstrip-tabs-collection)
199+
* [TabStrip Tab `HeaderTemplate`](slug:tabstrip-header-template)

0 commit comments

Comments
 (0)