Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a value from a page to the layout in Blazor?

I have a layout (MainLayout.razor), and it has a flag called ShowFooter. On some pages, I want to be able to set that flag to true, and some others to false.

I haven't been able to find any clear instructions on how a page (i.e. a component with a route) can communicate with its layout. How could/should this be done in Blazor?

Note: You might suggest having 2 layouts, one with and one without the footer, but that wouldn't really solve my problem, I want to be able to show and hide the footer at different times on the same page. Plus, this is just one scenario where there is a need to communicate between the layout and the page. There are also countless others.

like image 658
Arad Avatar asked Dec 08 '20 12:12

Arad


People also ask

How do you pass a value from one page to another in Blazor?

By using Blazor route parameters, you can pass values from one page to another page. Use NavigationManager to pass a value and route the parameter to another page. Follow this example to achieve passing values from one page to another.

How do you pass data from parent to child in Blazor?

When you call callApi in the FirstChild , it will change it's own data , if you want to change the parent's data , you need to pass a parameter to FirstChild which will be a function to call when the span is clicked and that will call the Parent 's callApi .


2 Answers

The simplest way to do that is to define a public Boolean property named ShowFooter in the MainLaout component, as follows:

public bool ShowFooter {get; set;}

And to cascade a reference to MainLaout component to given components, by wrapping the markup within a CascadingValue component whose Value attribute is set to this, like this:

@inherits LayoutComponentBase


<CascadingValue Value="this">
     <div class="sidebar">
        <NavMenu />
    </div>
    <div class="main">
         <div class="content px-4">
            @Body
        </div>
    </div>
</CascadingValue>
@code
{
    public bool ShowFooter {get; set;}

     protected override void OnInitialized()
    {
      // Put here code that checks the value of ShowFooter and acts in 
      // accordance with your dear wishes

     }
}

Usage in Index.razor

@code{
     // Gets a reference to the MainLayout component
    [CascadingParameter]
    public MainLayout Layout { get; set; } 

    protected override void OnInitialized()
    {
        Layout.ShowFooter= true;
    
    }
}
like image 185
enet Avatar answered Oct 19 '22 18:10

enet


There are a few ways to do it:

  1. The ugliest: If you have two templates you can simply select the template you want to use with the following on the top of the page/component:

    @layout NoFooterLayoutName

  2. Use cascading value in the template ( What I would recommend for your scenerio):

<CascadingValue Value="Footer">
    <Child />
</CascadingValue>

Example fiddle: https://blazorfiddle.com/s/05spcuyk

And Doc: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/cascading-values-and-parameters?view=aspnetcore-5.0

  1. Create a State service and add it to startup as scoped. The state service with footer bool variable, and can then be injected into pages/components and variable used:

In startup.cs ConfigureService method:

services.AddScoped<AppState>();

Create AppState.cs class somewhere in your project (ideally a Services folder):

public class AppState 
{
   public bool ShowFooter { get; set; }
   public event Action StateChanged;
   private void NotifyStateChanged() => StateChanged?.Invoke();
}

Then inject it in your page/components so you can change the ShowFooter Element and in your template you can create event handler (not sure if necessary) for that triggers StateHasChanged():

@inject AppState _AppState;
@implements IDisposable
.
.
.
@code{
    protected override void OnInitialized()
    {
        _appState.StateChanged += StateChanged;
    }

    public void StateChanged()
    {
        StateHasChanged();
    }

    public void Dispose()
    {
        _appState.StateChanged -= StateChanged;
    }
}
like image 27
diegorodny Avatar answered Oct 19 '22 18:10

diegorodny