Skip to content

Commit 3574a52

Browse files
authored
Dynamic tabs support added. (#538)
1 parent ba7a76a commit 3574a52

File tree

5 files changed

+114
-32
lines changed

5 files changed

+114
-32
lines changed

BlazorBootstrap.Demo.RCL/Pages/Tabs/TabsDocumentation.razor

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@
9898
<SectionHeading Size="HeadingSize.H2" Text="Tab call back event: OnTabClicked" PageUrl="@pageUrl" HashTagName="tab-callback-event-on-tab-clicked" />
9999
<Demo Type="typeof(Tabs_Demo_12_Tab_Callback_Event_OnTabClicked)" />
100100

101+
<SectionHeading Size="HeadingSize.H2" Text="Dynamic tabs" PageUrl="@pageUrl" HashTagName="dynamic-tabs" />
102+
<Demo Type="typeof(Tabs_Demo_13_Dynamic_Tabs)" />
103+
101104
@code {
102105
private string pageUrl = "/tabs";
103106
private string title = "Blazor Tabs Component";
Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<Tabs>
22
@foreach (var customer in customers)
33
{
4-
<Tab IsActive="selectedCustomer == customer" OnTabClicked="async () => await OnTabClickedAsync(customer)" Title="@customer.CustomerName">
4+
<Tab Title="@customer.CustomerName"
5+
IsActive="selectedCustomer.CustomerId == customer.CustomerId"
6+
OnTabClicked="() => OnTabClicked(customer)">
57
<Content>
68
<div class="mt-3">
79
This is the placeholder content for the <b>@customer.CustomerName</b> tab.
@@ -17,24 +19,11 @@
1719
}
1820

1921
@code {
20-
private List<Customer> customers = new()
21-
{
22-
new Customer(1, "Marvin Klein"),
23-
new Customer(2, "Vikram Reddy"),
24-
new Customer(3, "Bandita PA"),
25-
new Customer(4, "Daina JJ")
26-
};
22+
private List<Customer> customers = new() { new(1, "Marvin Klein"), new(2, "Vikram Reddy"), new(3, "Bandita PA"), new(4, "Daina JJ") };
2723

28-
private Customer? selectedCustomer;
24+
private Customer selectedCustomer = default!;
2925

30-
protected override void OnInitialized()
31-
{
32-
selectedCustomer = customers.First();
33-
}
26+
protected override void OnInitialized() => selectedCustomer = customers.First();
3427

35-
private Task OnTabClickedAsync(Customer customer)
36-
{
37-
selectedCustomer = customer;
38-
return Task.CompletedTask;
39-
}
28+
private void OnTabClicked(Customer customer) => selectedCustomer = customer;
4029
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<Tabs @ref="tabs">
2+
@foreach (var customer in customers)
3+
{
4+
<Tab Title="@customer.CustomerName"
5+
OnTabClicked="() => OnTabClicked(customer)">
6+
<Content>
7+
<div class="mt-3">
8+
This is the placeholder content for the <b>@customer.CustomerName</b> tab.
9+
</div>
10+
</Content>
11+
</Tab>
12+
}
13+
</Tabs>
14+
15+
@if (selectedCustomer is not null)
16+
{
17+
<div class="mt-3">Selected customer: <b>@selectedCustomer.CustomerName</b></div>
18+
}
19+
20+
<Button Color="ButtonColor.Success" Class="mt-3" @onclick="AddCustomer">Add customer</Button>
21+
22+
@code {
23+
Tabs tabs = default!;
24+
25+
private List<Customer> customers = new() { new(1, "Marvin Klein"), new(2, "Vikram Reddy"), new(3, "Bandita PA"), new(4, "Daina JJ") };
26+
27+
private Customer selectedCustomer = default!;
28+
29+
protected override void OnInitialized() => selectedCustomer = customers.Last();
30+
31+
private void AddCustomer()
32+
{
33+
var count = customers.Count;
34+
var customer = new Customer(count + 1, $"Customer {count + 1}");
35+
customers.Add(customer);
36+
//selectedCustomer = customer; NOTE: this line is not required
37+
tabs.InitializeRecentTab(showTab: true);
38+
}
39+
40+
private void OnTabClicked(Customer customer) => selectedCustomer = customer;
41+
}

blazorbootstrap/Components/Tabs/Tabs.razor.cs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ protected override async Task OnInitializedAsync()
4848
{
4949
objRef ??= DotNetObjectReference.Create(this);
5050

51-
Attributes ??= new();
52-
if(IsVertical)
51+
Attributes ??= new Dictionary<string, object>();
52+
53+
if (IsVertical)
5354
Attributes.Add("aria-orientation", "vertical");
5455

5556
await base.OnInitializedAsync();
@@ -97,6 +98,30 @@ public async Task bsShowTab(string activeTabId, string previousActiveTabId)
9798
await OnShowing.InvokeAsync(args);
9899
}
99100

101+
/// <summary>
102+
/// Initializes the most recently added tab, optionally displaying it.
103+
/// </summary>
104+
/// <param name="showTab">Specifies whether to display the tab after initialization.</param>
105+
public void InitializeRecentTab(bool showTab)
106+
{
107+
if (!tabs?.Any() ?? false) return;
108+
109+
ExecuteAfterRender(
110+
async () =>
111+
{
112+
var tab = tabs!.LastOrDefault();
113+
114+
if (tab is { Disabled: false })
115+
{
116+
await JS.InvokeVoidAsync("window.blazorBootstrap.tabs.initializeNewTab", tab.ElementId, objRef);
117+
118+
if (showTab)
119+
await ShowTabAsync(tab);
120+
}
121+
}
122+
);
123+
}
124+
100125
/// <summary>
101126
/// Selects the first tab and show its associated pane.
102127
/// </summary>
@@ -106,7 +131,7 @@ public async Task ShowFirstTabAsync()
106131

107132
var tab = tabs!.FirstOrDefault(x => !x.Disabled);
108133

109-
if (tab != null)
134+
if (tab is { Disabled: false })
110135
await ShowTabAsync(tab);
111136
}
112137

@@ -119,7 +144,7 @@ public async Task ShowLastTabAsync()
119144

120145
var tab = tabs!.LastOrDefault(x => !x.Disabled);
121146

122-
if (tab != null)
147+
if (tab is { Disabled: false })
123148
await ShowTabAsync(tab);
124149
}
125150

@@ -135,14 +160,14 @@ public async Task ShowTabByIndexAsync(int tabIndex)
135160

136161
var tab = tabs[tabIndex];
137162

138-
if (tab != null && !tab.Disabled)
163+
if (tab is { Disabled: false })
139164
await ShowTabAsync(tab);
140165
}
141166

142167
/// <summary>
143168
/// Selects the tab by name and show its associated pane.
144169
/// </summary>
145-
/// <param name="tabName"></param>
170+
/// <param name="tabName">The name of the tab to select.</param>
146171
public async Task ShowTabByNameAsync(string tabName)
147172
{
148173
if (!tabs?.Any() ?? false) return;
@@ -155,14 +180,12 @@ public async Task ShowTabByNameAsync(string tabName)
155180

156181
internal void AddTab(Tab tab)
157182
{
158-
if (tab != null)
159-
{
160-
tabs?.Add(tab);
183+
tabs!.Add(tab);
161184

162-
if (tab is { IsActive: true, Disabled: false }) activeTab = tab;
185+
if (tab is { IsActive: true, Disabled: false })
186+
activeTab = tab;
163187

164-
StateHasChanged(); // This is mandatory
165-
}
188+
StateHasChanged(); // This is mandatory
166189
}
167190

168191
/// <summary>
@@ -172,9 +195,9 @@ internal async Task SetDefaultActiveTabAsync()
172195
{
173196
if (!tabs?.Any() ?? false) return;
174197

175-
activeTab ??= tabs?.FirstOrDefault(x => !x.Disabled)!;
198+
activeTab ??= tabs!.FirstOrDefault(x => !x.Disabled)!;
176199

177-
if (activeTab != null)
200+
if (activeTab is not null)
178201
await ShowTabAsync(activeTab);
179202
}
180203

blazorbootstrap/wwwroot/blazor.bootstrap.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,32 @@ window.blazorBootstrap = {
630630
});
631631
});
632632
},
633+
initializeNewTab: (tabId, dotNetHelper) => {
634+
let tabEl = document.getElementById(tabId);
635+
if (tabEl == null)
636+
return;
637+
638+
tabEl?.addEventListener('show.bs.tab', (event) => {
639+
// event.target --> active tab
640+
// event.relatedTarget --> previous active tab (if available)
641+
dotNetHelper.invokeMethodAsync('bsShowTab', event.target?.id, event.relatedTarget?.id);
642+
});
643+
tabEl?.addEventListener('shown.bs.tab', (event) => {
644+
// event.target --> active tab
645+
// event.relatedTarget --> previous active tab
646+
dotNetHelper.invokeMethodAsync('bsShownTab', event.target?.id, event.relatedTarget?.id);
647+
});
648+
tabEl?.addEventListener('hide.bs.tab', (event) => {
649+
// event.target --> current active tab
650+
// event.relatedTarget --> new soon-to-be-active tab
651+
dotNetHelper.invokeMethodAsync('bsHideTab', event.relatedTarget?.id, event.target?.id);
652+
});
653+
tabEl?.addEventListener('hidden.bs.tab', (event) => {
654+
// event.target --> previous active tab
655+
// event.relatedTarget --> new active tab
656+
dotNetHelper.invokeMethodAsync('bsHiddenTab', event.relatedTarget?.id, event.target?.id);
657+
});
658+
},
633659
show: (elementId) => {
634660
let navTabsEl = document.getElementById(elementId);
635661
if (navTabsEl != null)

0 commit comments

Comments
 (0)