Blazor CascadingValue - c#

My goal is to get some data passed to common layout code. Code snippets of what I have but the value of linkedCyclones is not cascading to the lower component NavLinkedCyclones.
Not sure who to pass data into a layout component. I thought the cascade would do the trick but I'm either doing it wrong or it doesn't work the same way with layouts.
The LinkedSetIds is always null in the NavLinkedCyclones.razor
I welcome any suggestions.
NavCycloneMenu.razor
<CascadingValue Value="#linkedCyclones" Name="LinkedSets">
<AuthorizeView Roles="Admin, Tier2, Tier3">
<Authorized>
<li class="nav-item px-3">
<NavLink class="nav-link" href="CycloneCalculator/GasMix">
<span class="oi oi-beaker" aria-hidden="true"></span> Gas Mix
</NavLink>
</li>
</Authorized>
</AuthorizeView>
<AuthorizeView>
<Authorized>
<li class="nav-item px-3">
<NavLink class="nav-link" href="CycloneCalculator/CycloneSizing">
<span class="oi oi-calculator" aria-hidden="true"></span> Cyclone Sizing
</NavLink>
</li>
</Authorized>
</AuthorizeView>
</CascadingValue>
#code {
private int[] linkedCyclones { get; set; }
protected override void OnInitialized()
{
linkedCyclones = new int[] { 101, 202, 303 };
}
}
GasMix.razor
#layout CycloneLayout;
<div>
<h1>Gas Mix</h1>
</div>
CycloneLayout.razor
#inherits LayoutComponentBase
<div class="sidebar">
<NavCycloneMenu />
</div>
<div class="main">
<div class="top-row px-4 auth">
<LoginDisplay />
<a class="top-row-text" href="https://www.example.com/" target="_blank">About</a>
</div>
<div class="content px-4">
<NavLinkedCyclones />
#Body
</div>
</div>
NavLinkedCyclones.razor
<fieldset>
<legend>Linked Cyclones</legend>
#for (int i = 0; i < LinkedSetIds.Length - 1; i++)
{
<img class="img-linked-cyclone" src="images/CycloneLogoNoWhite.png" alt="Cyclone"> Cyclone #(i+1)
<div class="oi oi-arrow-thick-right" aria-hidden="true"></div>
<div class="oi oi-arrow-thick-right" aria-hidden="true"></div>
<div class="oi oi-arrow-thick-right" aria-hidden="true"></div>
}
<img class="img-linked-cyclone" src="images/CycloneLogoNoWhite.png" alt="Cyclone"> Cyclone #LinkedSetIds.Length
</fieldset>
#code{
[CascadingParameter(Name = "LinkedSets")]
public int[] LinkedSetIds { get; set; }
}

Related

How to change my NavMenu after user Login?

Hello I am stuck on this problem today.
I have a web interface where you can log in.
See picture:
On the left side I have my navmenu with the different choices.
After the user has logged in I want the navmenu to change and show other menu items (change password, change email).
The problem is that with blazor the navmenu is always applied to all pages.
Here is my NavMenu.razor
<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" href="login">
<span class="oi oi-account-login" aria-hidden="true"></span> Login
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="register">
<span class="oi oi-plus" aria-hidden="true"></span> Registrieren
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-check" aria-hidden="true"></span> Email Prüfen
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-question-mark" aria-hidden="true"></span> Passwort Vergessen
</NavLink>
</div>
</nav>
How do I make it so that my page gets its own navmenu after login and the existing one does not change?
Here is my html part of my login page
<html>
<h1 class="title">Login</h1>
<br/>
<div class="row px-3">
<RadzenCard class="card">
<div class="row">
<div class="col-3" style="">
<h3 style="margin-top:3%; margin-left:30px;">Benutzername</h3>
</div>
<div class="col-5">
<RadzenTextBox #bind-Value=#_username class="email_input"></RadzenTextBox>
<p hidden=#errorMessagesEmail.NoSyntaxError class="errorMail">Ungültige Email Adresse</p>
<p hidden=#errorMessagesEmail.NoEmptyEmail class="errorMail">Bitte Email Adresse eingeben</p>
</div>
</div>
<br/>
<div class="row">
<div class="col-3">
<h3 style="margin-top:3%; margin-left:30px; ">Passwort</h3>
</div>
<div class="col-5">
<RadzenPassword #bind-Value=#_password class="password_input"></RadzenPassword>
<p hidden=#errorMessagesPassword.NoEmptyPassword class="passwordMessage">Bitte Passwort eingeben</p>
<p hidden=#errorMessagesPassword.RightCredentials class="passwordMessage">Benutzername oder Passwort falsch</p>
<p hidden=#errorMessagesPassword.NotToManyRequest class="passwordMessage">Zu viele Anfragen mit einem falschen Passwort</p>
<br/>
<p class="errorMail">#_loginErrorMessages</p>
<p hidden=#_logInFailed class="passwordMessage">Erfolgreich</p>
</div>
</div>
</RadzenCard>
<RadzenButton Click=#OnLogin class="rz-button" ButtonType="ButtonType.Submit" Text="Login"></RadzenButton>
</div>
Thanks for all Answers
If you need any more infos just let me Know
;P
You use <AuthorizeView> to display differing content depending on the user's authorization status. This is called authorization.
For authenticated users, you can display content specific to them inside the <Authorized>.
If user is not logged in and you want to show content only of unathorized users, place the content inside <NotAuthorized> element.
To enable authorization in your pages you need to enable authentication state in App.razor
App.razor:
<CascadingAuthenticationState>
<Router AppAssembly="#typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)"/>
<FocusOnNavigate RouteData="#routeData" Selector="h1"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="#typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
Then you need to update your NavMenu to show links accordingly, for example when a user is not logged in, show the login and registration menu but not email or password menu because those last 2 menus I assume are for authenticated users only.
NavMenu.razor
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">BlazorApp1</a>
<button title="Navigation menu" class="navbar-toggler" #onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<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>
<AuthorizeView>
<NotAuthorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="login">
<span class="oi oi-account-login" aria-hidden="true"></span> Login
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="register">
<span class="oi oi-plus" aria-hidden="true"></span> Registrieren
</NavLink>
</div>
</NotAuthorized>
</AuthorizeView>
<AuthorizeView>
<Authorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-check" aria-hidden="true"></span> Email Prüfen
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-question-mark" aria-hidden="true"></span> Passwort Vergessen
</NavLink>
</div>
</Authorized>
</AuthorizeView>
</nav>
</div>
#code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
Output:
You are looking for AuthorizeView Component. For details see documentation.
Basically you can have NavMenu.razor like this:
<AuthorizeView>
<Authorized>
<AuthorizedMenu />
</Authorized>
<NotAuthorized>
<NotAuthorizedMenu />
</NotAuthorized>
</AuthorizeView>
with your current code being moved to the new NotAuthorizedMenu.razor component.
This should work, but I'm not at my VS atm to test it fully. So some changes might be needed.
Please note (from documentation):
The AuthorizeView component can be used in the NavMenu component (Shared/NavMenu.razor) to display a NavLink component (NavLink), but note that this approach only removes the list item from the rendered output. It doesn't prevent the user from navigating to the component.

Blazor NavMenu does not get default with #page "/" and querystring

We have a starting page that is declared like this.
#page "/"
#inherits PageBase
#using GroupTool.Blazor.Core
#using Microsoft.Extensions.Configuration
#using GroupTool.Blazor.Extensions
#inject IConfiguration _configuration
#using Microsoft.AspNetCore.Authorization
#attribute [Authorize]
#inject DialogService _dialogService
<div class="container linkpagecontainer">
<div class="col-md-12 linkpagerowdiv">
<div class="row linkpagerow">
<div class="col col-md-5 d-none d-sm-flex flex-column grouplistbox groupboxleft">
The MainLayout used with this page is like this.
#inherits LayoutComponentBase
#using Microsoft.AspNetCore.Components.Authorization
#inject ILocalStorageService localStore
#inject NavigationManager NavigationManager
#using Blazored.LocalStorage;
#using Wur.GroupTool.Blazor.Core.Infrastructure;
<AuthorizeView>
<Authorized>
<div class="page mainpage">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4 auth">
#if (DataLoaded)
{
<div class="main-header"><h2>#CourseDetails.Name #CourseCode Period: #Year-#PeriodNumber</h2></div>
}
<LoginDisplay />
</div>
<div class="content px-4 maincontent">
<RadzenNotification />
<RadzenTooltip />
<RadzenDialog />
#Body
</div>
</div>
</div>
</Authorized>
<NotAuthorized>
<div class="page">
<div class="main">
<div class="top-row px-4 auth">
<LoginDisplay />
</div>
<div class="content px-4">
#Body
</div>
</div>
</div>
</NotAuthorized>
</AuthorizeView>
As you can see a NavMenu is added which is like this.
<div class="top-row pl-4 navbar navbar-dark navbarheader">
<a class="navbar-brand" href=""><img src="css/images/WUR_W.png" height="20"/> GroupTool</a>
<button class="navbar-toggler" #onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<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-people" aria-hidden="true"></span> Groups
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="linkgroups">
<span class="oi oi-link-intact" aria-hidden="true"></span> Link Groups
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="schedule">
<span class="oi oi-calendar" aria-hidden="true"></span> Schedule
</NavLink>
</li>
</ul>
</div>
<footer class="footer">
<div class="container-fluid">
© #DateTime.Today.Year WUR<br />version #System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
</div>
</footer>
#code {
private bool collapseNavMenu = false;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
Now the problem is that when I go to the startpage without a query string the menu shows like this.
When however I add a querystring like f.i. so.
https://localhost:44381/?CourseId=13890
The menu show up without the default set.
What do I need to do to get that working?
==EDIT==
I think it's a bug in Blazor. Take a look here: https://code-maze.com/query-strings-blazor-webassembly/ The article explains how to use query strings in Blazor but notice what happens to the menu in the images on the page. Exactly my problem.
==EDIT==
Reported a bug on Github: https://github.com/dotnet/aspnetcore/issues/31312
If I've understood your question correctly, what you want is to change
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
to
<NavLink class="nav-link" href="/" Match="NavLinkMatch.All">
this will allow the navlink matching to work with queryparameters

Cascading values and EventCallback in Blazor with layout component

I have three components that I want to pass values and eventcallbacks through:
First I have MainLayout that is a LayoutComponent
#inherits LayoutComponentBase
<div class="cms-container">
<div class="header">
<div class="header-logo">
CMS
</div>
<div class="header-settings">
<div class="header-settings__alert">
<i class="fa fa-bell"></i>
<div class="header-settings__alert--no">
<div class="header-settings__alert--no__text">
2
</div>
</div>
<ul class="cms-dropdown">
<li class="cms-dropdown__alert">
<span class="cms-dropdown__alert--status"><i class="fa fa-info-circle font-danger"></i></span>
<span class="cms-dropdown__alert--left">Följ upp händelse</span><span class="cms-dropdown__alert--right">1 dgr</span>
</li>
<li class="cms-dropdown__alert">
<span class="cms-dropdown__alert--status"><i class="fa fa-info-circle font-success"></i></span>
<span class="cms-dropdown__alert--left">Tidrapport behöver lämnas in</span><span class="cms-dropdown__alert--right">3 dgr</span>
</li>
</ul>
</div>
<div class="header-settings__org">
<span class="header-settings__org--text">
Kanal10.se
</span>
<ul class="cms-dropdown">
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-tasks"></i>
</div>
<div class="cms-dropdown__normal--text">Uppgifter</div>
</li>
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-users"></i>
</div>
<div class="cms-dropdown__normal--text">Användare</div>
</li>
</ul>
</div>
<div class="header-settings__account">
<i class="fa fa-user"></i>
<ul class="cms-dropdown">
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-user"></i>
</div>
<div class="cms-dropdown__normal--text">Min profil</div>
</li>
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-money-check"></i>
</div>
<div class="cms-dropdown__normal--text">Lönebesked</div>
</li>
</ul>
</div>
<div class="header-settings__system">
<div class="header-settings__system--icon">
<i class="fa fa-cog"></i>
</div>
<ul class="cms-dropdown">
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-bars"></i>
</div>
<div class="cms-dropdown__normal--text">Menyer</div>
</li>
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-users"></i>
</div>
<div class="cms-dropdown__normal--text">Användare</div>
</li>
<li class="cms-dropdown__normal">
<div class="cms-dropdown__normal--icon">
<i class="fa fa-shield-alt"></i>
</div>
<div class="cms-dropdown__normal--text">Behörighetsgrupper</div>
</li>
</ul>
</div>
</div>
</div>
<div class="LeftNav">
<NavMenu />
</div>
<TelerikRootComponent>
<div class="cms-content">
#Body
</div>
</TelerikRootComponent>
<div class="footer">
<div class="footer-body">
<div class="footer-body__left">
</div>
<div class="footer-body__right">
<CascadingValue Value="visible">
<SaveAndCancelBtns OnBtnAction="?" />
</CascadingValue>
</div>
</div>
</div>
</div>
<BlazoredToasts Position="Blazored.Toast.Configuration.ToastPosition.TopCenter"
Timeout="3"
IconType="IconType.FontAwesome"
SuccessClass="success-toast-override"
SuccessIcon="fa fa-thumbs-up" />
#code {
private bool visible = false;
}
Then I have a child component called Buttons.razor
#if (visible == true)
{
<div class="footer-body__right--item">
<button class="btn btn-primary" #onclick="Save" type="submit">Save</button>
</div>
<div class="footer-body__right--item">
<button class="btn btn-cancel" #onclick="Cancel">Cancel</button>
</div>
}
[Parameter] public EventCallback<string> OnBtnAction { get; set; }
[Parameter] public bool visible { get; set; }
private void Save()
{
OnBtnAction.InvokeAsync("Save");
}
private void Cancel()
{
OnBtnAction.InvokeAsync("Cancel");
}
}
And then I have the component razor page called pageDetail.razor
#page "/pages/detail/{Id}"
#page "/pages/detail"
<div class="wrapper">
<div class="cms-content__title">
<div class="cms-content__title-left">
Page Detail
</div>
</div>
<div class="cms-content__page">
<div class="cms-content__page-all">
#if (cmsPage == null)
{
<ErrorMessage Message="Loading..." />
}
else
{
<div class="col-6">
<EditForm Model="cmsPage" OnValidSubmit="SavePage">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="PageTitle">Page Title</label>
<InputText #bind-Value="#cmsPage.PageTitle" class="form-control" id="PageTitle"></InputText>
</div>
<div class="form-group">
<label for="PageTitle">Page Descr</label>
<InputTextArea #bind-Value="#cmsPage.PageDescr" class="form-control" id="PageTitle"></InputTextArea>
</div>
<div class="form-group">
<label for="PageTitle">Page Url</label>
<InputText #bind-Value="#cmsPage.UrlName" class="form-control" id="PageTitle"></InputText>
</div>
<div class="form-group">
<label for="PageTitle">Page Type</label><br />
<TelerikComboBox Data="#cmsPageTypes" TextField="PageType" Width="100%" ValueField="PageTypeId" #bind-Value="selectedValue">
</TelerikComboBox>
<ValidationMessage For="#(() => cmsPage.PageTypeId)" />
</div>
<div class="form-group">
<label for="PageTitle">Parent Page</label><br />
<TelerikTreeView Data="#cmsPages" OnItemClick="#OnItemClickHandler">
<TreeViewBindings>
<TreeViewBinding IdField="PageId" TextField="PageTitle" ParentIdField="ParentId" HasChildrenField="false"></TreeViewBinding>
</TreeViewBindings>
</TelerikTreeView>
</div>
<button class="btn btn-primary" type="submit">Save</button>
<button class="btn btn-danger" #onclick="DeletePage">Delete</button>
<button class="btn btn-info" #onclick="BackToList">Back To List</button>
</EditForm>
</div>
}
</div>
</div>
</div>
#code{
"not sure how to implement the event button action"
}
What I want is to:
On PageDetail set a parameter for visible and if it is true show the buttons in Buttons.razor or hide them
When clicking on a buttton in buttons.razor handle the event on PageDetail.razor for the EditForm there
The thing is how to handle the component that is a LayoutComponent. Not sure how it fits in the logic.
As you can see I have started implementing it but am not sure of how to connect the different parts.
Grateful for help!
Peter
I'd recommend looking at this article: https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/ but you're part of the way there by using the <CascadingParameter> in your layout.
In your case I'm not keen on using a boolean visible as a cascading parameter, it's a bit simplistic. The cascading value is also in the wrong place for this as it needs to wrap both the #Body render and the buttons.
I'd create a state class and cascade that class to any child that wants to use it, by wrapping the #Body and the <SaveAndCancelBtns ..>
<CascadingValue Value="buttonState" >
<TelerikRootComponent>
<div class="cms-content">
#Body
</div>
</TelerikRootComponent>
<div class="footer">
<div class="footer-body">
<div class="footer-body__left">
</div>
<div class="footer-body__right">
<SaveAndCancelBtns />
</div>
</div>
</div>
</CascadingValue>
You also need to add a value in the layout code:
ButtonStates buttonState = new ButtonStates();
The ButtonStates class should provide the values and events you need, e.g.
public class ButtonStates
{
public bool Visible { get; private set; }
// etc
}
Rather than put all the code here I've created a simple sample repo on github for you:
https://github.com/conficient/CascadingStateExample
Note that I've just used a simple state container and event to pass events from it. EventCallback<T> is specifically used to wire up events between Razor components.

MVC C# Carousel Image

i have been trying to create a carousel image on my MVC application. The below snippet from W3 was just used as an example. The result was the images displayed ont he webpage one below eachother. Do i need to do anything else on the MVC application to resolve this?
<div class="container">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
</ol>
<!-- Wrapper for slides -->
<div class="carousel-inner">
<div class="item active">
<img src="https://www.w3schools.com/bootstrap/ny.jpg" alt="Los Angeles" style="width:100%;">
</div>
<div class="item">
<img src="https://www.w3schools.com/bootstrap/chicago.jpg" alt="Chicago" style="width:100%;">
</div>
<div class="item">
<img src="https://www.w3schools.com/bootstrap/newyork.jpg" alt="New york" style="width:100%;">
</div>
</div>
<!-- Left and right controls -->
<a class="left carousel-control" href="#myCarousel" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
I had the same requirement sometime ago and I used below code, look if it works for you.
<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
#{
var first = true;
}
#foreach (var item in ViewBag.Images)
{
<div class="carousel-item #(first?Html.Raw("active"):Html.Raw(""))">
<img class="d-block w-100" src="#item.Image" alt="#item.Name">
</div>
first = false;
}
</div>
<a class="carousel-control-prev" href="#carouselExampleControls" role="button"
data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleControls" role="button"
data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
Please Try this.I hope your problem is solved
<div id="demo" class="carousel slide" data-ride="carousel">
<ul class="carousel-indicators">
<li data-target="#demo" data-slide-to="0" class="active"></li>
<li data-target="#demo" data-slide-to="1"></li>
<li data-target="#demo" data-slide-to="2"></li>
</ul>
<div class="carousel-inner" role="listbox">
#{int i = 0;}
#foreach (var item in Model)
{
i++;
var active = i == 1 ? "active" : "";
<div class="carousel-item #active">
<img src="#Url.Content(#item.FilePath)" alt="">
</div>
}
</div>
<a class="carousel-control-prev" href="#demo" data-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#demo" data-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
</div>

Sharing a single property across multiple cshtml pages in Blazor

I'm struggling to share a properties value across components in Blazor. Basically I have a button with an onclick event this sets a value on a function depending on the value another cshtml page should react to the value and it doesn't. The issue is that because both cshtml pages inherit the same function they have their own instance of the function. Here's my code so far:
the Function:
public class MenuFunctions : BlazorComponent, IMenuFunctions
{
public bool CollapseNavMenu
{
get ; set;
}
public void ToggleNavMenu()
{
CollapseNavMenu = !CollapseNavMenu;
}
}
The main button on NavMenuToggleComponent.cshtml:
#inherits MenuFunctions
<div class="pl-4 navbar navbar-dark">
<button class="navbar-toggler navbar-brand main-button" title="MENU" onclick=#ToggleNavMenu>
MENU
</button>
</div>
my NavMenu.cshtml file:
#inherits MenuFunctions
<div class="#(CollapseNavMenu ? "collapse" : null)" onclick=#ToggleNavMenu>
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="home">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="frontpage">
<span class="oi oi-home" aria-hidden="true"></span> Front Page
</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="" Match=NavLinkMatch.All>
<span class="oi oi-account-login" aria-hidden="true"></span> Login
</NavLink>
</li>
</ul>
</div>
putting it all together in my MainLayout.cshtml
#inherits BlazorLayoutComponent
<NavMenuToggleComponent></NavMenuToggleComponent>
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
About
<NavLink class="nav-link pull-right" href="logout">
<span class="oi oi-account-logout" aria-hidden="true"></span> Logout
</NavLink>
</div>
<div class="content px-4">
#Body
</div>
</div>
so when I click the button in NavMenuToggleComponent.cshtml I want the CollapseNavMenu to react in the NavMenu.cshtml file
If I remove the use of the interface, then inject the components onto the pages as opposed to Inherit and then add the following into the startup:
services.AddSingleton<MenuFunctions>();
the pages will load, but I still get the same issue.
The solution here would be to bring the shared property to the place where it is common, in this case the MainLayout.cshtml and not make the components dependent on a common interface.
So the MainLayout.cshtml would hold the state in a new property and that property is bound to the two components.
You should not use DI for component classes, only for service providing classes and alike.

Categories