Bootstrap NavTab from Database - asp.net-core

I have the following table:
---------------------------
oName Dept
---------------------------
Roo IT
Max MKT
Tom MKT
Then I have the following script on my controller:
ViewBag.GetoName = (from a in _db.TbEmp
where a.Dept == "MKT"
select new {
a.oName
}
).ToList();
I want to load the list above into a navTab on my View. How can I do that? So the navTab bootstrap would be:
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#max">Max</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tom">Tom</a>
</li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade show active" id="max">
<p>Content1</p>
</div>
<div class="tab-pane fade" id="tom">
<p>Content2</p>
</div>
</div>
Please advice.
Thank you.

If you want oName to be nav_link name,and Dept to be Content.Here is a demo:
<ul class="nav nav-tabs">
#{ var count = 0;}
#foreach (var sample in ViewBag.GetoName)
{
if (count == 0)
{
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="##sample.oName">#sample.oName</a>
</li>
}
else {
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="##sample.oName">#sample.oName</a>
</li>
}
count++;
}
</ul>
<div id="myTabContent" class="tab-content">
#{ var count1 = 0;}
#foreach (var sample in ViewBag.GetoName)
{
if (count1 == 0)
{
<div class="tab-pane fade show active" id="#sample.oName">
<p>#sample.Dept</p>
</div>
}
else
{
<div class="tab-pane fade" id="#sample.oName">
<p>#sample.Dept</p>
</div>
}
count1++;
}
</div>
result:

Related

How can I have a specific tab refreshed on post in Asp.Net Core Razor tabbed pages

I have a tabbed Razor page, on load there is no data to be retrieved from server, active tab set for first tab. However, when I update data on one tab and post it I want the page to get only data for that tab. What I have so far is
<ul class="nav nav-tabs" id="PTWTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="PTW-tab" data-toggle="tab" href="#PTW" aria-controls="ptw" aria-selected="true" style="width:200px">Permit To Work</a>
</li>
<li class="nav-item">
<a class="nav-link" id="HazId-tab" data-toggle="tab" href="#HazId" aria-controls="hazid" aria-selected="false" style="width:200px">Hazard Identification</a>
</li>
<li class="nav-item">
<a class="nav-link" id="GasTest-tab" data-toggle="tab" href="#GasTest" aria-controls="gt" aria-selected="false" style="width:200px">Gas Testing</a>
</li>
<li class="nav-item">
<a class="nav-link" id="IsoCert-tab" data-toggle="tab" href="#IsoCert" aria-controls="isocert" aria-selected="false" style="width:200px">Isolation Certificate</a>
</li>
</ul>
and cshtml is:
public async Task<IActionResult> OnPostIsoCertAsync(int? PTWNo)
{
if (!ModelState.IsValid)
{
return Page();
}
var newIsoCert = await _context.ICContents.FindAsync(PTWNo);
if (newIsoCert == null)
{
return NotFound();
}
if (await TryUpdateModelAsync<ICContent>(
newIsoCert,
"ICContent",
c => c.IdICD,
c => c.IsoStep,
c => c.EquipmentID,
c => c.EquipmentDescription,
c => c.EnSource,
c => c.IsType,
c => c.IsMethod,
c => c.LockNo,
c => c.PreparedBy,
c => c.ImplementedBy,
c => c.VerifiedBy,
c => c.IsStatus))
{
await _context.SaveChangesAsync();
return Page();
}
return Page();
}
there is also an OnGet procedure and html to display data
when I update data on one tab and post it I want the page to get only data for that tab.
If you'd like to just update a specific tab section content, as #Tavershima mentioned, you can try to dynamically render some partial view using Ajax on JavaScript. The following simple demo is for your reference.
#page
#model WebGlobalSearch.MenuTabModel
#{
ViewData["Title"] = "MenuTab";
}
<h1>MenuTab</h1>
<ul class="nav nav-tabs" id="PTWTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="PTW-tab" data-toggle="tab" href="#PTW" aria-controls="ptw" aria-selected="true" style="width:200px">Permit To Work</a>
</li>
<li class="nav-item">
<a class="nav-link" id="HazId-tab" data-toggle="tab" href="#HazId" aria-controls="hazid" aria-selected="false" style="width:200px">Hazard Identification</a>
</li>
<li class="nav-item">
<a class="nav-link" id="GasTest-tab" data-toggle="tab" href="#GasTest" aria-controls="gt" aria-selected="false" style="width:200px">Gas Testing</a>
</li>
<li class="nav-item">
<a class="nav-link" id="IsoCert-tab" data-toggle="tab" href="#IsoCert" aria-controls="isocert" aria-selected="false" style="width:200px">Isolation Certificate</a>
</li>
</ul>
<div class="tab-content">
<div id="PTW" class="tab-pane fade active show">
<h3>Permit To Work</h3>
<br />
<div class="tab-c">
<partial name="PTW" />
</div>
</div>
<div id="HazId" class="tab-pane fade">
<h3>Hazard Identification</h3>
</div>
<div id="GasTest" class="tab-pane fade">
<h3>Gas Testing</h3>
<br />
<div class="tab-c">
<partial name="GasTest" />
</div>
</div>
<div id="IsoCert" class="tab-pane fade">
<h3>Isolation Certificate</h3>
</div>
</div>
#Html.AntiForgeryToken()
#section scripts{
<script>
function UpdateGasTestFunc() {
$.ajax({
type: "POST",
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
url: "MenuTab?handler=UpdateGasTest",
//data: data,
success: function (res) {
$("#GasTest").find("div.tab-c").html(res);
}
});
}
</script>
}
OnPostUpdateGasTest handler
public IActionResult OnPostUpdateGasTest()
{
return Partial("GasTest");
}
Content of partial view GasTest
Gas Testing Page #DateTime.Now.ToString()
<input type="button" value="Update" id="btn_update" onclick="UpdateGasTestFunc()" />
Test Result
I just wanted to avoid javascript and only update the tab that concern me
Under the scenario you described in your question, normally if browser user submit updated data to server without from JavaScript, server would return new response to browser client and full page will be re-rendered, not just a part of html content.
Update:
What I want is to post, refresh page and show the tab I post from
To dynamically reset active tab after page reloaded, you can refer to the following code snippet.
$(function () {
var active_tab_id = localStorage.getItem('activetab');
if (active_tab_id != null) {
//console.log(active_tab_id);
$('#PTWTab a[id="' + active_tab_id + '"]').tab('show');
}
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
//console.log($(e.target).attr("id"));
localStorage.setItem('activetab', $(e.target).attr('id'));
});
})

How to correctly output data from the database to the razor

I have 2 drop-down menus
<div class="dropdown">
<button class=" js-dropdownDate dropdown-toggle" type="button" data-toggle="dropdown" data-value="#Model.WeekNumberDayStart" id="periodTypeNumber">
<span class="toggle-text">First</span>
<span class="dropdown-caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation">
<a class="active" role="menuitem" tabindex="-1" href="#" data-value="1">First</a>
</li>
<li role="presentation">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="2">Second</a>
</li>
<li role="presentation" data-value="3">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="3">Third</a>
</li>
<li role="presentation" data-value="4">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="4">Fourth</a>
</li>
<li role="presentation" data-value="5">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="5">Fifth</a>
</li>
</ul>
</div>
<div class="dropdown">
<button class=" js-dropdownDate dropdown-toggle" type="button" data-toggle="dropdown" id="periodTypeDay" data-value="#Model.DayNubmerOfWeek">
<span class="toggle-text">monday</span>
<span class="dropdown-caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation" data-value="1">
<a class="active" role="menuitem" tabindex="-1" href="#" data-value="1">monday</a>
</li>
<li role="presentation" data-value="2">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="2">tuesday</a>
</li>
<li role="presentation" data-value="3">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="3">wednesday</a>
</li>
<li role="presentation" data-value="4">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="4">thursday</a>
</li>
<li role="presentation" data-value="5">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="5">friday </a>
</li>
<li role="presentation" data-value="6">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="6">saturday</a>
</li>
<li role="presentation" data-value="7">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="7">sunday</a>
</li>
</ul>
</div>
and if the date from #Model.WeekNumberDayStart(int - like 1,2,3,4...) = data-value = "1" then need to write class = "active" otherwise just class = ""
maybe somehow it can be done differently through the menu itself through DropDownList?
and if the date from #Model.WeekNumberDayStart(int - like 1,2,3,4...)
= data-value = "1" then need to write class = "active" otherwise just class = ""
It cannot be achieved by menu itself. You need to use jquery code to achieve.
Since you have two dropdown menus, you need to distinguish the a tag of these two menus.
Therefore, you can add custom attributes and corresponding values to each group of a tags to ensure that the corresponding elements can be obtained in jquery.
Below is the class active binding for the first group of dropdown menu example.
<div class="dropdown">
<button class=" js-dropdownDate dropdown-toggle" type="button" data-toggle="dropdown" data-value="#Model.WeekNumberDayStart" id="periodTypeNumber">
<span class="toggle-text">First</span>
<span class="dropdown-caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation">
<a class="active" role="menuitem" tabindex="-1" href="#" data-value="1" droptype="WeekNumberDayStart">First</a>
</li>
<li role="presentation">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="2" droptype="WeekNumberDayStart">Second</a>
</li>
<li role="presentation" data-value="3">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="3" droptype="WeekNumberDayStart">Third</a>
</li>
<li role="presentation" data-value="4">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="4" droptype="WeekNumberDayStart">Fourth</a>
</li>
<li role="presentation" data-value="5">
<a class="" role="menuitem" tabindex="-1" href="#" data-value="5" droptype="WeekNumberDayStart">Fifth</a>
</li>
</ul>
</div>
jquery to change binding class active according to #Model.WeekNumberDayStart value:
<script>
$(function () {
$("a[droptype=WeekNumberDayStart]").each(function () {
$(this).removeClass("active");
if ($(this).attr("data-value") == $("#periodTypeNumber").attr("data-value")) {
$(this).addClass("active");
}
})
})
</script>

Bootstrap 4 tabs with VuesJS in a loop - can't go back to the first tab

I am using vueJS and Bootstrap tabs and can't get them to work properly. I can visit tab 1, tab 2, tab 3, tab 4, but then I can't go back to tab 1.
I can also go 1, 3, but then not 1 and 2. I can basically only go to the right
As these tabs are in a v-for loop, I add ids to each of them.
I have zero error/warning, each ID is unique.
<nav class="navbar navbar-expand-lg " style="width:100%;">
<div class=" navbar-collapse">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0" :id="'myTab'+form.id_item" role="tablist" style="display: flex; width:100%">
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a active" :id="'infosGenform-tab'+form.id_item" data-toggle="tab" :href="'#infosGenform'+form.id_item" role="tab" aria-controls="infosGenform" aria-selected="true">infosGenform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a " :id="'inscrform-tab'+form.id_item" data-toggle="tab" :href="'#inscrform'+form.id_item" role="tab" aria-controls="inscrform" aria-selected="true">inscrform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a" :id="'machineform-tab'+form.id_item" data-toggle="tab" :href="'#machineform'+form.id_item" role="tab" aria-controls="machineform" aria-selected="true">machineform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a " :id="'comform-tab'+form.id_item" data-toggle="tab" :href="'#comform'+form.id_item" role="tab" aria-controls="home" aria-selected="true">comform</a>
</li>
</ul>
</div>
</nav>
<div class="tab-content" :id="'myTabContent'+form.id_item">
<div class="tab-pane fade show active itra-light-grey-bgr" :id="'infosGenform'+form.id_item" role="tabpanel" aria-labelledby="infosGenform-tab">
1
</div>
<div class="tab-pane fade show itra-light-grey-bgr" :id="'inscrform'+form.id_item" role="tabpanel" aria-labelledby="inscrform-tab">
2
</div>
<div class="tab-pane fade show itra-light-grey-bgr" :id="'machineform'+form.id_item" role="tabpanel" aria-labelledby="machineform-tab">
3
</div>
<div class="tab-pane fade show itra-light-grey-bgr" :id="'comform'+form.id_item" role="tabpanel" aria-labelledby="comform-tab">
4
</div>
</div>
Is it something you already experienced?
Thanks a lot
I would avoid using jQuery and use vuejs instead to navigate tabs. Here is my approach.
In your tab navigation add this #click.prevent="showTab(1)". The .prevent is to prevent default action of going to another page. In your other navigation do the same i.e #click.prevent="showTab(n)".
This means you will have to add a new vuejs method showTab(value)like below.
showTab(value){
this.tab = value
}
In your tab content use vuejs show v-show="tab == 1" Find the full code below.
<template>
<div>
<nav class="navbar navbar-expand-lg " style="width:100%;">
<div class=" navbar-collapse">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0" :id="'myTab'+form.id_item" role="tablist" style="display: flex; width:100%">
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a active" :id="'infosGenform-tab'+form.id_item" #click.prevent="showTab(1)" role="tab" aria-controls="infosGenform"
aria-selected="true">infosGenform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a " :id="'inscrform-tab'+form.id_item" #click.prevent="showTab(2)" role="tab" aria-controls="inscrform"
aria-selected="true">inscrform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a" :id="'machineform-tab'+form.id_item" #click.prevent="showTab(3)" role="tab" aria-controls="machineform"
aria-selected="true">machineform</a>
</li>
<li class="nav-item nav-evt-li">
<a class="nav-link nav-evt-a " :id="'comform-tab'+form.id_item" #click.prevent="showTab(4)" role="tab" aria-controls="home"
aria-selected="true">comform</a>
</li>
</ul>
</div>
</nav>
<div class="tab-content" :id="'myTabContent'+form.id_item">
<div v-show="tab == 1" class="tab-pane fade show itra-light-grey-bgr" :id="'infosGenform'+form.id_item" role="tabpanel"
aria-labelledby="infosGenform-tab">
1
</div>
<div v-show="tab == 2" class="tab-pane fade show itra-light-grey-bgr" :id="'inscrform'+form.id_item" role="tabpanel"
aria-labelledby="inscrform-tab">
2
</div>
<div v-show="tab == 3" class="tab-pane fade show itra-light-grey-bgr" :id="'machineform'+form.id_item" role="tabpanel"
aria-labelledby="machineform-tab">
3
</div>
<div v-show="tab == 4" class="tab-pane fade show itra-light-grey-bgr" :id="'comform'+form.id_item" role="tabpanel"
aria-labelledby="comform-tab">
4
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
tab: 1
}
},
methods: {
showTab(value){
this.tab = value
}
}
}
</script>
I hope this answer will help.

How to create NavMenu with collapsible submenu in .Net Core Blazor app

I am trying to create a blazor navmenu which has a shape like this
item a
item b
when I click on item b it expands with sub menu like this and clicking on subitems, new pages open
item a
item b
subitem 1
subitem 2
I just edited the original blazor app but no success. The button appears but it doesn't collapse submenu. any idea?
<div class="#NavMenuCssClass" #onclick="#ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch Data
</NavLink>
</li>
<li class="dropdown">
<button data-toggle="collapse" data-target="#demo">Collapsible</button>
<div id="demo" class="collapse">
<ul>
<li class="nav-item px-3">
<NavLink class="nav-link" href="meeting">
<span class="oi oi-plus" aria-hidden="true"></span> Meetings
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="conference">
<span class="oi oi-list-rich" aria-hidden="true"></span> Conferences
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="event">
<span class="oi oi-list-rich" aria-hidden="true"></span> Events
</NavLink>
</li>
</ul>
</div>
</li>
</ul>
Do not use the data-toggle and data-target for it.
These are used by boostrap.js however you do not want to modify the DOM in that way.
What you do instead is to use an if statement and thus let Blazor take care of the rendering:
<NavLink class="nav-link" #onclick="()=>expandSubNav = !expandSubNav">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
#if (expandSubNav)
{
<NavLink class="expand-menu" href="">
<span>Sub1</span>
</NavLink>
<NavLink class="" href="">
<span>Sub2</span>
</NavLink>
}
And put the expandSubNav field into your code section:
#code {
private bool expandSubNav;
}
You can try this solution if you have more submenus
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">System</a>
<button class="navbar-toggler" #onclick="() => ToggleNavMenu(navSubmenu)">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="#NavMenuCssClass">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="() => ToggleNavMenu(NavSubmenu.None)" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="() => TogleSubmenu(NavSubmenu.First)">
<span class="oi oi-list-rich" aria-hidden="true"></span> Submenu 1
</NavLink>
</li>
#if (navSubmenu == NavSubmenu.First)
{
<li class="nav-item px-5">
<NavLink class="nav-link" #onclick="() => ToggleNavMenu()" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-5">
<NavLink class="nav-link" #onclick="() => ToggleNavMenu()" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch Data
</NavLink>
</li>
}
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="() => TogleSubmenu(NavSubmenu.Second)">
<span class="oi oi-list-rich" aria-hidden="true"></span> Submenu 2
</NavLink>
</li>
#if (navSubmenu == NavSubmenu.Second)
{
<li class="nav-item px-5">
<NavLink class="nav-link" #onclick="() => ToggleNavMenu()" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-5">
<NavLink class="nav-link" #onclick="() => ToggleNavMenu()" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch Data
</NavLink>
</li>
}
</ul>
</div>
#code {
private enum NavSubmenu
{
None,
First,
Second
}
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private NavSubmenu navSubmenu = NavSubmenu.None;
private bool collapseNavMenu = true;
private void ToggleNavMenu(NavSubmenu? submenu = null)
{
collapseNavMenu = !collapseNavMenu;
navSubmenu = submenu ?? navSubmenu;
}
private void TogleSubmenu(NavSubmenu submenu)
{
if (navSubmenu == submenu)
navSubmenu = NavSubmenu.None;
else
navSubmenu = submenu;
}
}
<div class="nav-link" #onclick="()=>expandSubNav = !expandSubNav">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</div>
#if (expandSubNav)
{
<NavLink class="expand-menu" href="">
<span>Sub1</span>
</NavLink>
<NavLink class="" href="">
<span>Sub2</span>
</NavLink>
}
use div instead of NAVLINK. Navlink reloads the page and reset the expandSubNav.
My Solution, after problems with not closing on click the submenu:
works on Mobile:
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" href="">MyPrgramm</a>
<button class="navbar-toggler" type="button" #onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
<div class="#NavMenuCssClass" #onclick="ToggleNavMenu">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<NavLink class="nav-link text-dark" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link text-dark" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Menu-II
</NavLink>
</li>
<li class="nav-item dropdown show">
<NavLink class="nav-link dropdown-toggle" #onclick="() => expandSubNavSettings = !expandSubNavSettings" id="navbarDropdown" >
<span class="oi oi-list-rich" aria-hidden="true"></span> Menu III
</NavLink>
#if (expandSubNavSettings)
{
<li class="dropdown-menu show" aria-labelledby="navbarDropdown" #onclick="() => expandSubNavSettings = !expandSubNavSettings">
<li class="nav-item">
<NavLink class="nav-link text-dark" href="fetchdata">
<span class="oi oi-fork" aria-hidden="true"></span> Fetch
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link text-dark" href="counter">
<span class="oi oi-command" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link text-dark" href="home">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
</li>
}
</li>
</ul>
</div>
</div>
</nav>
#code {
bool collapseNavMenu = true;
private bool expandSubNavSettings;
string baseMenuClass = "navbar-collapse d-sm-inline-flex flex-sm-row-reverse";
string NavMenuCssClass => baseMenuClass + (collapseNavMenu ? " collapse" : "");
void ToggleNavMenu()
{
if(!expandSubNavSettings)
{
collapseNavMenu = !collapseNavMenu;
}
}
}
(End result) I struggled quite a bit with submenus and ended up using this in my project:
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">Submenu master</a>
<button class="navbar-toggler" #onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="#NavMenuCssClass">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="()=>ToggleNavMenu()" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="()=>ToggleSubmenu()">
<span class="oi oi-menu" aria-hidden="true"></span> Menu
</NavLink>
</li>
#if (expandMenu)
{
<li class="nav-item px-4" #onclick="ToggleNavMenu">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-4" #onclick="ToggleNavMenu">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
}
</ul>
</div>
#code {
private bool collapseNavMenu = true;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private bool expandMenu;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
expandMenu = false;
}
private void ToggleSubmenu()
{
expandMenu = !expandMenu;
}
}
Implement Sub-menu by using Bootstrap
Default template of Blazor generate collapse class inside #media in NavMenu.razor.css which interferes with Bootstrap's submenu collapse so we need to rename it to something else.
/* NavMenu.razor.css */
/* Add */
.sidebar-collapse {
display: none;
}
/* Modify */
#media (min-width: 641px) {
...
.sidebar-collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}
On NavMenu.razor replace the same class name inside code block
/* NavMenu.razor */
private string? NavMenuCssClass => collapseNavMenu ? "sidebar-collapse" : null;
Remove #onclick="ToggleNavMenu" from nav parent div
<div class="#NavMenuCssClass">
<nav class="flex-column">
...
</nav>
</div>
Add Sub-Menu Items.
Classes has-submenu, nav-submenu and nav-subitem are optional but will be used for styling later
<div class="nav-item has-submenu px-3">
<NavLink class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#userSubMenu"> <!-- <= this id -->
<span class="oi oi-list-rich" aria-hidden="true"></span> Users
</NavLink>
<ul class="nav-submenu collapse list-unstyled" id="userSubMenu"> <!-- <= and this id must match -->
<li class="nav-subitem">
<NavLink href="users/add">
<span class="oi oi-plus" aria-hidden="true"></span> Add
</NavLink>
</li>
<li class="nav-subitem">
<NavLink href="users/list">
<span class="oi oi-people" aria-hidden="true"></span> View
</NavLink>
</li>
</ul>
</div>
Bootstrap 4.x
Add js files in index.html
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
Bootstrap 5.x
Add js files in index.html
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
On NavLink Replace data-toggle with data-bs-toggle and data-target with data-bs-target
Sub-menu should be working now.
Additional Styling
Add these styles to NavMenu.razor.css
/* Custom Styles */
.nav-item ::deep .nav-link i {
width: 2rem;
font-size: 1.1rem;
}
::deep .nav-item.has-submenu > a {
position: relative;
}
::deep .nav-item.has-submenu > a:after {
content: "\e02f";
position: absolute;
right: 15px;
color: white;
font-family: "Icons";
font-weight: 400;
font-size: 13px;
transform: rotateZ(90deg);
transform-origin: left;
transition: transform .5s ease;
}
::deep .nav-item.has-submenu > a.collapsed:after {
transform: rotateZ(0deg);
}
.nav-item ::deep .nav-submenu .nav-subitem a {
padding-left: 3rem;
text-decoration: none;
}
.nav-item ::deep .nav-submenu .nav-subitem a i {
width: 2rem;
font-size: 1.1rem;
}
If you would like to have perfect look of sub menu items, here is the example:
<li class="nav-item px-3">
<NavLink class="nav-link" href="cart" #onclick="()=>expandSubMenu= !expandSubMenu">
<span class="oi oi-cart" aria-hidden="true"></span> Cart
</NavLink>
#if (expandSubMenu)
{
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="cart/1">
<span class="oi oi-file" aria-hidden="true"></span> Sub-1
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="cart/2">
<span class="oi oi-bar-chart" aria-hidden="true"></span> Sub-1
</NavLink>
</li>
</ul>
}
</li>
you also need to add expandSubMenu property to the code block
#code {
private bool collapseNavMenu = true;
private bool expandSubMenu;//add
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
I tried with the same css class available in nav menu and made the submenu looks better.
<div class="#NavMenuCssClass" #onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" #onclick="()=>expandSubNav=!expandSubNav">
<span class="oi oi-plus" aria-hidden="true"></span>Admin
</NavLink>
#if (expandSubNav)
{
<div class="nav-item px-3">
<NavLink class="nav-link" href="device">
<span class="oi oi-arrow-circle-right"></span>Sub-menu 1
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-arrow-circle-right"></span>Sub-menu 2
</NavLink>
</div>
}
</div>
</nav>
#code {
private bool collapseNavMenu = true;
private bool expandSubNav = false;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
I took a approach with jQuery and also made the menu responsive :
A complete sample can be downloaded from here
I was not happy with the solutions so after a lot of thinking I came up with the following one. This does work on normal browser and mobile.
For browser:
Submenu only collapse after a click on it.
Submenu collapse after the click on the title (Webassembly).
Submenus did not collapse if some other sections are clicked.
For mobile:
Page starts with Navmenu collapsed
Submenu only collapses after click on it.
Navmenu did collapse after selection (if not the submenu is collapsed by it)
Navmenu collapses after click on the title (Webassembly).
The trick was to remove the NavMenuToggle in the <div class="#NavMenuCssClass nav-scrollable ..."> element to get more control over the each element inside the div. I also changed some of the variables to make more sense for me.
Here is the full code:
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid" #onclick="CloseEveryMenu">
<a class="navbar-brand" href="">WebAssembly</a>
<button title="Navigation menu" class="navbar-toggler">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="#NavMenuCssClassCollapse nav-scrollable">
<nav class="flex-column">
<div class="nav-item px-3" #onclick="ToggleNavMenu">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3" #onclick="ToggleNavMenu">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" #onclick="ToggleSubMenu">
<span class="oi" aria-hidden="true">Configuration</span>
</NavLink>
#if (subMenuExpanded)
{
<div class="nav-item px-3" #onclick="CloseNavMenu">
<NavLink class="nav-link" href="#">
<span class="oi oi-arrow-circle-right"></span>Sub-menu 1
</NavLink>
</div>
<div class="nav-item px-3" #onclick="CloseNavMenu">
<NavLink class="nav-link" href="#">
<span class="oi oi-arrow-circle-right"></span>Sub-menu 2
</NavLink>
</div>
}
</div>
<div class="nav-item px-3" #onclick="ToggleNavMenu">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
</nav>
</div>
#code {
private bool navMenuExpanded = false;
private bool subMenuExpanded = false;
private string? NavMenuCssClassCollapse => navMenuExpanded ? null : "collapse";
private void ToggleNavMenu() => navMenuExpanded = !navMenuExpanded;
private void ToggleSubMenu() => subMenuExpanded = !subMenuExpanded;
private void CloseNavMenu() => navMenuExpanded = false;
private void CloseSubMenu() => subMenuExpanded = false;
private void CloseEveryMenu()
{
CloseSubMenu();
ToggleNavMenu();
}
}
Please don't forget to upvote the question (and the answer if you like it)!

Materialize dropdown menu shows horizontal scrollbar rather than expanding past its parent when the text is longer. Anyone know why?

I seem to be able to find the question posted on here and google about the same issue in bootstrap, but i'm not able to find answers for the same issue in Materialize
I'm new to bootstrap and everything i've tried hasn't solved it. I'd be grateful if anyone knows why it's doing this and how to override it.
Thank you!
the live page is here
i've set drop downs to fire on 'about' and 'profile'
the script:
<script>
var $ = jQuery;
(function($){
$(function(){
$('.dropdown-button').dropdown({
inDuration: 300,
outDuration: 225,
constrain_width: false,
hover: false,
alignment: 'right',
gutter: 0,
belowOrigin: true,
});
$('.button-collapse').sideNav({menuWidth: 240, activationWidth: 70});
}); // end of document ready
})(jQuery); // end of jQuery name space
</script>
nav bar:
<nav>
<div class="nav-wrapper">
<a class="brand-logo hide-on-med-and-down left" href="http://focallocal.org">Focallocal</a>
<ul class="hide-on-small-and-down left">
<li class="text-icon">
<a class="dropdown-button" href="http://about.focallocal.org" data-activates="nav-about" title="About Us">
<i class="mdi-action-info"></i>
<span>About Us</span>
</a>
</li>
<li class="text-icon">
<a href="http://news.focallocal.org/" title="Happy News">
<i class="mdi-device-brightness-high"></i>
<span>Happy News</span>
</a>
</li>
<li class="text-icon">
<a href="http://action.focallocal.org/" title="Action">
<i class="mdi-action-get-app"></i>
<span>Action Centre</span>
</a>
</li>
<li class="text-icon">
<a href="http://activities.focallocal.org" title="Activities">
<i class="mdi-maps-directions-walk"></i>
<span>Activities</span>
</a>
</li>
<li class="text-icon">
<a href="http://gather.focallocal.org/" title="Gather">
<i class="mdi-image-flare"></i>
<span> Gather </span>
</a>
</li>
<li class="text-icon">
<a href="http://shop.focallocal.org/" title="Shop">
<i class="mdi-action-shop-two"></i>
<span> Shop</span>
</a>
</li>
<li class="text-icon">
<a class="dropdown-button" href="#" data-activates="nav-projects" title="Projects">
<i class="mdi-action-info"></i>
<span>Projects</span>
</a>
</li>
</ul>
<ul class="right">
<li class="text-icon">
<a href="http://discuss.focallocal.org" target="_blank" title="Chat">
<i class="mdi-communication-dialpad"></i>
<span>Discuss</span>
</a>
</li>
<li class="text-icon">
<a href="https://trello.com/invite/b/SwMdGGcX/dbf6c3cebca7e2214ac0df3a57b1881f/build-the-movement" target="_blank" title="Missions">
<i class="mdi-content-create"></i>
<span>Missions</span>
</a>
</li>
<li class="text-icon">
<a href="#" title="coming soon">
<i class="mdi-action-perm-media"></i>
<span>Profile</span>
</a>
</li>
</ul>
<ul id="user-dropdown" class="dropdown-content">
<li>Log in</li>
<li>Register</li>
</ul>
<a class="button-collapse" href="#" data-activates="nav-mobile"><i class="mdi-navigation-menu"></i></a>
</div>
</nav>
dropdowns:
<ul id="nav-about" class="dropdown-content">
<li>
About Us
</li>
<li>
Hire Us
</li>
<li>
Community Values
</li>
<li>
F.A.Q
</li>
<li>
The Road to Focallocal
</li>
<li>
Will we Succeed?
</li>
<li>
Focallocal in the news
</li>
<ul id="nav-projects" class="dropdown-content">
<li>
<a href="http://action.focallocal.org/">Action Center
</a>
</li>
<li>
<a href="http://brightertomorrowmap.com/">Brighter Tomorrow Map
</a>
</li>
<li>
<a href="http://morehappiness.focallocal.org/">More Happiness
</a>
</li>