Reputation: 315
Here I want to pass some title to the mainlayout.razor page so that my components or pages can update the title of header. Is there any possible way in blazor to do this ? Any help will be appreciated.
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4 bg-success">
<button onclick="toggleNav()">
<span class="oi oi-menu"></span>
</button>
<div class="text-center">
hey there
</div>
</div>
<div class="content px-4">
@Body
</div>
</div>
</div>
@code
{
}
and my child component is a router page with @page directive to navigate between pages i want that component to update this mainlayout is there any possible way ? Thanks in advance for any help.
Regards,
Upvotes: 21
Views: 8734
Reputation: 409
While this has already been answered, I just want to provide the approach I've been using as well, which seems like more work than the accepted answer. But I'm providing it anyway :-)
In my Program.cs I use DI with a base model
builder.Services.AddSingleton<BaseViewModel>();
And in my BaseViewModel I have
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _title;
public string Title
{
get => _title;
set
{
if (_title != value)
{
_title = value;
OnPropertyChanged();
}
}
}
In my MainLayout I inject the ViewModel
@inject BaseViewModel ViewModel
Then in my OnInitializedAsync method in my MainLayout I bind an OnPropertyChanged event to update my MainLayout
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
ViewModel.PropertyChanged += OnPropertyChanged;
}
private async void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
await InvokeAsync(StateHasChanged);
}
In your child page, inject the same ViewModel
@inject BaseViewModel ViewModel
Now when you update the Title property in a child page, it should also update in your MainLayout
Upvotes: 0
Reputation: 2403
From .Net 8 (available on Nov. 2023), Blazor will support Section outlets, which are designed for this:
_Imports.razor
@using Microsoft.AspNetCore.Components.Sections
MainLayout.razor
<SectionOutlet SectionName="page-title" />
MyPage.razor
<SectionContent SectionName="page-title">My Page Title</SectionContent>
Upvotes: 13
Reputation: 45596
You should wrap the view portion of the MainLayout component with the CascadingValue component whose value is a reference to the MainLayout itself, so that you can reference the MainLayout component, say, from the Counter component, from which you assign a value string to the property Title defined in the MainLayout component. This property also contain a call to the StateHasChanged method to refresh the display...
@page "/counter"
// Gets a reference to the MainLayout component
[CascadingParameter]
public MainLayout Layout { get; set; }
protected override void OnInitialized()
{
Layout.Title = "Greetings from Counter";
}
@inherits LayoutComponentBase
<CascadingValue Value="this">
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
@Title
<LoginDisplay />
<a href="https://learn.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<div class="content px-4">
@Body
</div>
</div>
</div>
</CascadingValue>
@code
{
private string title;
public string Title
{
get => title;
set
{
title = value;
InvokeAsync(() => StateHasChanged());
}
}
}
Upvotes: 26