mxmissile
mxmissile

Reputation: 11673

Blazor CascadingParameter is always null

New to Blazor, having trouble getting a CascadingParameter to populate from my MainLayout.razor:

@code
{
    private Toasts Toasts { get; set; }
}
        
<Toasts @ref="@Toasts" />
    
<CascadingValue Value="Toasts">
    @Body
</CascadingValue>

And Index.razor page:

[CascadingParameter]
public Toasts Toasts { get; set; }

public async Task PackageChanged(string value)
{
   Toasts.Something(value); //Toasts is null here
}

And finally Toasts.razor:

@code {

    private string Message { get; set; }

    public void Something(string message)
    {
        Message = message;
        StateHasChanged();
    }
}

@Message

This code below frustratingly works, but I'd like to cascade just the one component (<Toasts />) instead of the whole layout:

<CascadingValue Value="@this">
    <Toasts @ref="@Toasts" />
    @Body
</CascadingValue>

And then index:

[CascadingParameter]
public MainLayout Layout { get; set; }

 public async Task PackageChanged(string value)
 {
      Layout.Toasts.Something(value); //this behaves as expected
 }

Upvotes: 3

Views: 8328

Answers (2)

enet
enet

Reputation: 45596

This code is working for me

MainLayout...partial code

<div class="main">
        <div class="top-row px-4">
            <Toasts @ref="Toasts" />
        </div>

        @if (Toasts != null)
        {
            <CascadingValue Value="@Toasts">
                @Body
            </CascadingValue>
        }
 </div>

@code
{
    protected Toasts Toasts;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            StateHasChanged();
        }
    }
 }

The following solution, in which we cascade a reference to MainLayout, and then retrieve a reference to the Toasts component, is a bit more effective than the one above, as it does not require the MainLayout to render a second time.

MainLayout...partial code

<div class="main">
        <div class="top-row px-4">
            <Toasts @ref="Toasts" />
        </div>

         <CascadingValue Value="this">
            @Body
         </CascadingValue>     
 </div>

@code
{
    public Toasts Toasts { get; set; }
 } 

Index.razor

@page "/"

@code{
   
    [CascadingParameter]
    public MainLayout Layout { get; set; }
    
   
    protected override void OnInitialized()
    {
        // Reference the Toasts component's methods and properties
        // Note: You must not pass parameter values to the Toasts
        // component from here. You'll get a warning, or perhaps 
        // an error.
 
        Layout.Toasts.Something("Pass a message to the 
                                Something method");
    }

}

Upvotes: 4

Surinder Singh
Surinder Singh

Reputation: 1450

This statement in MainLayout.razor do not work

<Toasts @ref="@Toasts" />

But this statement works and cascading parameter in index.razor is not null

@code
{
    private Toasts Toasts= new();
}

Seems that Blazor do not allow to pass element references as cascading parameter but only allows object and other variables. I do not have full context of your requirements, but you can try implementing Toasts as a service.

Upvotes: 1

Related Questions