12
votes

I have a Blazor app with a MainLayout page, which has a @Body to load the actual page content.

In my case Index.razor is loaded inside the MainLayout page.

Is there a way to call a method from the child page (Index.razor) that lives in the parent page; MainLayout.razor?

Example:

MainLayout.razor

<div class="content">
<ul class="menu">
  <li>menu item 1</li>
</ul>

@Body

</div>

@code
{
    public async Task Test()
    {
        await JsRuntime.InvokeAsync<object>("console.log", "test parent");
    }
}

Index.razor

<h1>This is the index page</h1>
<button @onclick="(async () => await btn_clicked())">Call parent method</button>

@code
{
    // Call method in MainLayout
    public async Task btn_clicked()
    {
        await parent.Test();
    }
}
2
you don't need the async lamda any more. You can just use @onclick=btn_clicked - Neville Nazerane

2 Answers

11
votes

You can do this with the combination of cascading values and EventCallback.

First, create an event call back for your Test. To do so, add the following code in your MainLayout.razor.

EventCallback btn_clicked => EventCallback.Factory.Create(this, Test);

Or, to make sure you only create this object once, you can use the following:

EventCallback _btn_clicked = EventCallback.Empty;
EventCallback btn_clicked  {
    get {
        if (_btn_clicked.Equals(EventCallback.Empty))
            _btn_clicked = EventCallback.Factory.Create(this, Test);
        return _btn_clicked;
    }
}

Next, make sure you cascade this event callback down your body.

<CascadingValue Value=btn_clicked >
    @Body
</CascadingValue>

Now, in your Index.razor code, set the property:

[CascadingParameter]
public EventCallback btn_clicked { get; set; }
6
votes

Thanks. The first answer was exactly what I needed, though I needed to pass in a parameter, so it's the same as laid out, except:

In MainLayout.razor:

public EventCallback<string> EventName => EventCallback.Factory.Create<string>(this, MethodName);

In Index.razor:

[CascadingParameter]
protected EventCallback<string> EventName { get; set; }

To call the method:

EventName.InvokeAsync("Name");