diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/TabsDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/TabsDocumentation.razor
index e1372d53d..1f61ee62e 100644
--- a/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/TabsDocumentation.razor
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/TabsDocumentation.razor
@@ -69,28 +69,28 @@
-
- Event Name |
- Description |
-
+
+ Event Name |
+ Description |
+
-
- OnHiding |
- This event fires when a new tab is to be shown (and thus the previous active tab is to be hidden). |
-
-
- OnHidden |
- This event fires after a new tab is shown (and thus the previous active tab is hidden). |
-
-
- OnShowing |
- This event fires on tab show, but before the new tab has been shown. |
-
-
- OnShown |
- This event fires on tab show after a tab has been shown. |
-
+
+ OnHiding |
+ This event fires when a new tab is to be shown (and thus the previous active tab is to be hidden). |
+
+
+ OnHidden |
+ This event fires after a new tab is shown (and thus the previous active tab is hidden). |
+
+
+ OnShowing |
+ This event fires on tab show, but before the new tab has been shown. |
+
+
+ OnShown |
+ This event fires on tab show after a tab has been shown. |
+
@@ -123,6 +123,13 @@
+
+
+ In the following example, we are removing the inactive tab by name. The focus will not be lost with this active tab.
+
+
+
+
@code {
private const string pageUrl = RouteConstants.Demos_Tabs_Documentation;
private const string pageTitle = "Blazor Tabs";
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/Tabs_Demo_15_Remove_Inactive_Tab_by_Name.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/Tabs_Demo_15_Remove_Inactive_Tab_by_Name.razor
new file mode 100644
index 000000000..e9fd91b4c
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Tabs/Tabs_Demo_15_Remove_Inactive_Tab_by_Name.razor
@@ -0,0 +1,55 @@
+
+
+
+
+ @foreach (var customer in customers)
+ {
+
+
+
+
+ This is the placeholder content for the @customer.CustomerName tab.
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+@code {
+ Tabs tabsRef = default!;
+
+ int count = 1;
+ private List customers = default!;
+
+ protected override void OnInitialized()
+ {
+ customers = new() {
+ new(1, "Marvin Klein"),
+ new(2, "Vikram Reddy"),
+ new(3, "Bandita PA"),
+ new(4, "Dan H"),
+ new(5, "Joe JJ"),
+ new(6, "Rose KK")
+ };
+ count = customers.Count;
+ }
+
+ private void RemoveCustomerVikram()
+ {
+ var customer = customers.FirstOrDefault(c => c.CustomerName == "Vikram Reddy");
+ if (customer != null)
+ {
+ customers.Remove(customer);
+ tabsRef.RemoveTabByName(customer.CustomerId.ToString());
+ }
+ }
+}
diff --git a/blazorbootstrap/Components/Core/BlazorBootstrapComponentBase.cs b/blazorbootstrap/Components/Core/BlazorBootstrapComponentBase.cs
index e5386389f..6a16ea1ca 100644
--- a/blazorbootstrap/Components/Core/BlazorBootstrapComponentBase.cs
+++ b/blazorbootstrap/Components/Core/BlazorBootstrapComponentBase.cs
@@ -8,6 +8,8 @@ public abstract class BlazorBootstrapComponentBase : ComponentBase, IDisposable,
private bool isDisposed;
+ internal Queue> queuedTasks = new();
+
#endregion
#region Methods
@@ -15,17 +17,17 @@ public abstract class BlazorBootstrapComponentBase : ComponentBase, IDisposable,
///
protected override async Task OnAfterRenderAsync(bool firstRender)
{
- IsRenderComplete = true;
+ // process queued tasks
+ while (queuedTasks.TryDequeue(out var taskToExecute))
+ await taskToExecute.Invoke();
- await base.OnAfterRenderAsync(firstRender);
+ IsRenderComplete = true;
}
///
protected override void OnInitialized()
{
Id ??= IdUtility.GetNextId();
-
- base.OnInitialized();
}
public static string BuildClassNames(params (string? cssClass, bool when)[] cssClassList)
diff --git a/blazorbootstrap/Components/Grid/Grid.razor.cs b/blazorbootstrap/Components/Grid/Grid.razor.cs
index 2474f2cb9..57fe01434 100644
--- a/blazorbootstrap/Components/Grid/Grid.razor.cs
+++ b/blazorbootstrap/Components/Grid/Grid.razor.cs
@@ -35,8 +35,6 @@ public partial class Grid : BlazorBootstrapComponentBase
private int pageSize;
- private Queue> queuedTasks = new();
-
private bool requestInProgress = false;
private HashSet selectedItems = new();
@@ -56,18 +54,6 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
}
await base.OnAfterRenderAsync(firstRender);
-
- // process queued tasks
- while (true)
- {
- if (queuedTasks.Count == 0)
- break;
-
- var taskToExecute = queuedTasks.Dequeue();
-
- if (taskToExecute is not null)
- await taskToExecute.Invoke();
- }
}
protected override void OnInitialized()
diff --git a/blazorbootstrap/Components/Tabs/Tabs.razor.cs b/blazorbootstrap/Components/Tabs/Tabs.razor.cs
index f19354983..a97a5babb 100644
--- a/blazorbootstrap/Components/Tabs/Tabs.razor.cs
+++ b/blazorbootstrap/Components/Tabs/Tabs.razor.cs
@@ -14,7 +14,7 @@ public partial class Tabs : BlazorBootstrapComponentBase
private bool showLastTab = false;
- private List? tabs = new();
+ private List tabs = new();
#endregion
@@ -23,7 +23,8 @@ public partial class Tabs : BlazorBootstrapComponentBase
///
protected override async ValueTask DisposeAsyncCore(bool disposing)
{
- if (disposing) tabs = null;
+ if (disposing && tabs is not null)
+ tabs = null!;
await base.DisposeAsyncCore(disposing);
}
@@ -45,7 +46,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
}
// Show next available tab
- if (removedTabIndex > -1)
+ if (removedTabIndex > -1 || removedTabIndex == -99)
{
await ShowNextAvailableTabAsync(removedTabIndex);
removedTabIndex = -1;
@@ -69,8 +70,8 @@ protected override async Task OnInitializedAsync()
[JSInvokable]
public async Task bsHiddenTab(string activeTabId, string previousActiveTabId)
{
- var activeTab = tabs?.FirstOrDefault(x => x.Id == activeTabId);
- var previousActiveTab = tabs?.FirstOrDefault(x => x.Id == previousActiveTabId);
+ var activeTab = tabs.FirstOrDefault(x => x.Id == activeTabId);
+ var previousActiveTab = tabs.FirstOrDefault(x => x.Id == previousActiveTabId);
var args = new TabsEventArgs(activeTab?.Name!, activeTab?.Title!, previousActiveTab?.Name!, previousActiveTab?.Title!);
await OnHidden.InvokeAsync(args);
@@ -79,8 +80,8 @@ public async Task bsHiddenTab(string activeTabId, string previousActiveTabId)
[JSInvokable]
public async Task bsHideTab(string activeTabId, string previousActiveTabId)
{
- var activeTab = tabs?.FirstOrDefault(x => x.Id == activeTabId);
- var previousActiveTab = tabs?.FirstOrDefault(x => x.Id == previousActiveTabId);
+ var activeTab = tabs.FirstOrDefault(x => x.Id == activeTabId);
+ var previousActiveTab = tabs.FirstOrDefault(x => x.Id == previousActiveTabId);
var args = new TabsEventArgs(activeTab?.Name!, activeTab?.Title!, previousActiveTab?.Name!, previousActiveTab?.Title!);
await OnHiding.InvokeAsync(args);
@@ -89,8 +90,8 @@ public async Task bsHideTab(string activeTabId, string previousActiveTabId)
[JSInvokable]
public async Task bsShownTab(string activeTabId, string previousActiveTabId)
{
- var activeTab = tabs?.FirstOrDefault(x => x.Id == activeTabId);
- var previousActiveTab = tabs?.FirstOrDefault(x => x.Id == previousActiveTabId);
+ var activeTab = tabs.FirstOrDefault(x => x.Id == activeTabId);
+ var previousActiveTab = tabs.FirstOrDefault(x => x.Id == previousActiveTabId);
var args = new TabsEventArgs(activeTab?.Name!, activeTab?.Title!, previousActiveTab?.Name!, previousActiveTab?.Title!);
await OnShown.InvokeAsync(args);
@@ -99,8 +100,8 @@ public async Task bsShownTab(string activeTabId, string previousActiveTabId)
[JSInvokable]
public async Task bsShowTab(string activeTabId, string previousActiveTabId)
{
- var activeTab = tabs?.FirstOrDefault(x => x.Id == activeTabId);
- var previousActiveTab = tabs?.FirstOrDefault(x => x.Id == previousActiveTabId);
+ var activeTab = tabs.FirstOrDefault(x => x.Id == activeTabId);
+ var previousActiveTab = tabs.FirstOrDefault(x => x.Id == previousActiveTabId);
var args = new TabsEventArgs(activeTab?.Name!, activeTab?.Title!, previousActiveTab?.Name!, previousActiveTab?.Title!);
await OnShowing.InvokeAsync(args);
@@ -112,34 +113,23 @@ public async Task bsShowTab(string activeTabId, string previousActiveTabId)
/// Returns the cuurent active .
public Tab GetActiveTab() => activeTab;
- ///
- /// Initializes the most recently added tab, optionally displaying it.
- ///
- /// Specifies whether to display the tab after initialization.
- [Obsolete("This method is obseolete. Use `ShowRecentTabAsync` method instead.")]
- public void InitializeRecentTab(bool showTab)
- {
- if (showTab) showLastTab = true;
- }
-
///
/// Removes the tab by index.
///
///
- ///
public void RemoveTabByIndex(int tabIndex)
{
- if (!tabs?.Any() ?? true) return;
-
- if (tabIndex < 0 || tabIndex >= tabs!.Count) throw new IndexOutOfRangeException();
-
- var tab = tabs[tabIndex];
+ var tab = tabs.ElementAtOrDefault(tabIndex);
+ if (tab is null)
+ return;
- if (tab is null) return;
+ // If active tab is removed then select the next available tab.
+ if (activeTab.Id == tab.Id)
+ removedTabIndex = tabIndex;
+ else
+ removedTabIndex = -99;
- tabs!.Remove(tab);
-
- removedTabIndex = tabIndex;
+ tabs.Remove(tab);
}
///
@@ -148,17 +138,18 @@ public void RemoveTabByIndex(int tabIndex)
///
public void RemoveTabByName(string tabName)
{
- if (!tabs?.Any() ?? true) return;
-
- var tabIndex = tabs!.FindIndex(x => x.Name == tabName);
-
+ var tabIndex = tabs.FindIndex(x => x.Name == tabName);
if (tabIndex == -1) return;
var tab = tabs[tabIndex];
- tabs!.Remove(tab);
+ // If active tab is removed then select the next available tab.
+ if (activeTab.Id == tab.Id)
+ removedTabIndex = tabIndex;
+ else
+ removedTabIndex = -99;
- removedTabIndex = tabIndex;
+ tabs.Remove(tab);
}
///
@@ -166,9 +157,9 @@ public void RemoveTabByName(string tabName)
///
public async Task ShowFirstTabAsync()
{
- if (!tabs?.Any() ?? true) return;
-
- var tab = tabs!.FirstOrDefault(x => !x.Disabled);
+ var tab = tabs.FirstOrDefault(x => !x.Disabled);
+ if (tab is null)
+ return;
if (tab is { Disabled: false })
await ShowTabAsync(tab);
@@ -179,9 +170,9 @@ public async Task ShowFirstTabAsync()
///
public async Task ShowLastTabAsync()
{
- if (!tabs?.Any() ?? true) return;
+ if (tabs.Count == 0) return;
- var tab = tabs!.LastOrDefault(x => !x.Disabled);
+ var tab = tabs.LastOrDefault(x => !x.Disabled);
if (tab is { Disabled: false })
await ShowTabAsync(tab);
@@ -198,7 +189,7 @@ public async Task ShowLastTabAsync()
/// The zero-based index of the element to get or set.
public async Task ShowTabByIndexAsync(int tabIndex)
{
- if (!tabs?.Any() ?? true) return;
+ if (tabs.Count == 0) return;
if (tabIndex < 0 || tabIndex >= tabs!.Count) throw new IndexOutOfRangeException();
@@ -214,9 +205,9 @@ public async Task ShowTabByIndexAsync(int tabIndex)
/// The name of the tab to select.
public async Task ShowTabByNameAsync(string tabName)
{
- if (!tabs?.Any() ?? true) return;
+ if (tabs.Count == 0) return;
- var tab = tabs!.LastOrDefault(x => x.Name == tabName && !x.Disabled);
+ var tab = tabs.LastOrDefault(x => x.Name == tabName && !x.Disabled);
if (tab is not null)
await ShowTabAsync(tab);
@@ -224,7 +215,7 @@ public async Task ShowTabByNameAsync(string tabName)
internal void AddTab(Tab tab)
{
- tabs!.Add(tab);
+ tabs.Add(tab);
if (tab is { Active: true, Disabled: false })
activeTab = tab;
@@ -237,9 +228,9 @@ internal void AddTab(Tab tab)
///
internal async Task SetDefaultActiveTabAsync()
{
- if (!tabs?.Any() ?? true) return;
+ if (tabs.Count == 0) return;
- activeTab ??= tabs!.FirstOrDefault(x => !x.Disabled)!;
+ activeTab ??= tabs.FirstOrDefault(x => !x.Disabled)!;
if (activeTab is not null)
await ShowTabAsync(activeTab);
@@ -249,15 +240,20 @@ internal async Task SetDefaultActiveTabAsync()
private async Task ShowNextAvailableTabAsync(int removedTabIndex)
{
- if (!tabs?.Any() ?? true) return;
+ if (tabs.Count == 0) return;
- if (removedTabIndex < 0 || removedTabIndex > tabs!.Count) throw new IndexOutOfRangeException();
+ // Inactive tab is removed, just show the active tab.
+ if (removedTabIndex == -99)
+ {
+ await ShowTabAsync(activeTab);
+ return;
+ }
var tabIndex = 0;
- if (removedTabIndex == tabs!.Count)
- tabIndex = tabs!.Count - 1;
- else if (removedTabIndex < tabs!.Count)
+ if (removedTabIndex == tabs.Count)
+ tabIndex = tabs.Count - 1;
+ else if (removedTabIndex < tabs.Count)
tabIndex = removedTabIndex;
var tab = tabs[tabIndex];
@@ -271,10 +267,12 @@ private async Task ShowTabAsync(Tab tab)
if (!isDefaultActiveTabSet)
isDefaultActiveTabSet = true;
- await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.tabs.show", tab.Id);
+ queuedTasks.Enqueue(async () => await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.tabs.show", tab.Id));
if (tab?.OnClick.HasDelegate ?? false)
await tab.OnClick.InvokeAsync(new TabEventArgs(tab!.Name, tab.Title));
+
+ activeTab = tab!;
}
#endregion
diff --git a/docs/docs/05-components/tabs.mdx b/docs/docs/05-components/tabs.mdx
index 4712a6593..fd50827c7 100644
--- a/docs/docs/05-components/tabs.mdx
+++ b/docs/docs/05-components/tabs.mdx
@@ -680,4 +680,72 @@ In the following example, we are deleting tabs dynamically. Ensure that the **@k
}
```
-[See demo here.](https://demos.blazorbootstrap.com/tabs#remove-dynamic-tabs)
\ No newline at end of file
+[See demo here.](https://demos.blazorbootstrap.com/tabs#remove-dynamic-tabs)
+
+### Remove inactive tab
+
+In the following example, we are removing the inactive tab by name. The focus will not be lost with this active tab.
+
+
+
+```cshtml {} showLineNumbers
+
+
+
+
+ @foreach (var customer in customers)
+ {
+
+
+
+
+ This is the placeholder content for the @customer.CustomerName tab.
+
+
+
+
+ }
+
+
+
+
+
+
+
+```
+
+```cs {} showLineNumbers
+@code {
+ Tabs tabsRef = default!;
+
+ int count = 1;
+ private List customers = default!;
+
+ protected override void OnInitialized()
+ {
+ customers = new() {
+ new(1, "Marvin Klein"),
+ new(2, "Vikram Reddy"),
+ new(3, "Bandita PA"),
+ new(4, "Dan H"),
+ new(5, "Joe JJ"),
+ new(6, "Rose KK")
+ };
+ count = customers.Count;
+ }
+
+ private void RemoveCustomerVikram()
+ {
+ var customer = customers.FirstOrDefault(c => c.CustomerName == "Vikram Reddy");
+ if (customer != null)
+ {
+ customers.Remove(customer);
+ tabsRef.RemoveTabByName(customer.CustomerId.ToString());
+ }
+ }
+}
+```
+
+[See demo here.](https://demos.blazorbootstrap.com/tabs#remove-inactive-tab)
\ No newline at end of file