'Blazor, how can I change a component in MainLayout when I change page
I want to add a toolbar inside website, the toolbar change inside component on each page. For now, I have this but I want my toolbar to be like this. How could i make this toolbar to update depend on the page the user go ?
The toolbar would be in the MainLayout and need to change content with a switch (not the best option I think) or is it possible to give new content to MainLayout from the page content ?
This is the code for the banner component :
<div class="extend-space" style="left:@($"-{Convert.ToInt32(offsetX)}px")">
<div class="banner" style="left:@(Convert.ToInt32(offsetX)+"px");width:@(Convert.ToInt32(width)+"px");">
<div class="banner-title">
@if (Icon != null)
{<i id="banner-title-icon" class="icon fas fa-@Icon"></i>}
<h3 class="title">@Title</h3>
</div>
<div class="toolbar">
<span id="arrow-left" class="scrollable" onclick="lastTool()">
<i class="fas fa-angle-left arrow"></i>
</span>
<span id="toolbar">
@ChildContent
</span>
<span id="arrow-right" class="scrollable" onclick="nextTool()">
<i class="fas fa-angle-right arrow"></i>
</span>
</div>
</div>
ChildContent should be a list of buttons with function onclick on it so this is the part that need to update on each page.
I add an example of how I use it on a page :
<XLBanner Title="Catégories" Icon="sitemap">
<XLButton Icon="plus" Content="@SharedLocalizer["Add"]" OnClickFunction="@AddCategorie" />
<XLButton Icon="save" Content="@SharedLocalizer["Save"]" OnClickFunction="@Save" disabled="@(!UnsavedChanges)" />
<XLButton Icon="redo" Content="@SharedLocalizer["Reset"]" OnClickFunction="@DeleteUnsavedChanges" disabled="@(SelectedCategorie == null)" />
<XLButton Icon="trash-alt" Content="@SharedLocalizer["Remove"]" OnClickFunction="@SuppCategorie" disabled="@(SelectedCategorie == null)" />
<XLButton Icon="copy" Content="@SharedLocalizer["Copy"]" OnClickFunction="@CopyCategorie" disabled="@(SelectedCategorie == null)" />
<XLButton Icon="download" Content="@SharedLocalizer["Export"]" OnClickFunction="@Export" /
</XLBanner>
What would be needed to update is the XLButton and the OnClickFunction.
My banner has differents tools depend on the page exemple dashboard page, exemple categorie page
Solution 1:[1]
If I understand the question correctly a version of this should work for you.
Basically:
- Create a simple service that holds the menu data and has an event that is raised whenever the menu data changes and register it.
- Use a
DynamicComponent
in Layout that plugs into the service. - Trigger
StateHasChanged
on the Layout whenever the service raises a menu change event. - Set the menu you want in each page in
OnInitialized
.
Two "Menus" to work with:
Menu1.razor
<h3>Menu1</h3>
Menu2.razor
<h3>Menu2</h3>
A simple LayoutService
public class LayoutService
{
public Type MenuControl { get; private set; } = typeof(Menu1);
public Dictionary<string, object>? MenuParameters { get; private set; }
public event EventHandler? MenuChanged;
public void ChangeMenu(Type menu)
{
this.MenuControl = menu;
MenuChanged?.Invoke(this, EventArgs.Empty);
}
public void ChangeMenu(Type menu, Dictionary<string, object> parameters)
{
this.MenuParameters = parameters;
this.MenuControl = menu;
MenuChanged?.Invoke(this, EventArgs.Empty);
}
}
registered in Program.cs:
builder.Services.AddScoped<LayoutService>();
MainLayout.razor
@inherits LayoutComponentBase
@inject LayoutService LayoutService;
@implements IDisposable
<PageTitle>BlazorApp1</PageTitle>
<DynamicComponent Type=this.LayoutService.MenuControl Parameters=this.LayoutService.MenuParameters />
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
@code {
protected override void OnInitialized()
=> this.LayoutService.MenuChanged += this.MenuChanged;
private void MenuChanged(object? sender, EventArgs e)
=> this.InvokeAsync(StateHasChanged);
public void Dispose()
=> this.LayoutService.MenuChanged -= this.MenuChanged;
}
And example page:
@page "/"
@inject LayoutService LayoutService
Page Content
@code {
protected override void OnInitialized()
{
this.LayoutService.ChangeMenu(typeof(Menu1));
}
Solution 2:[2]
Don't get too focused on the layout as a single entity that you have to use for every page in the whole site. You can have as many Layout components as you want, and you can nest them just like you would with any class and derived class.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | MrC aka Shaun Curtis |
Solution 2 |