Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call method in MainLayout from a page component in Blazor

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();
    }
}
like image 533
Vivendi Avatar asked Sep 26 '19 18:09

Vivendi


3 Answers

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");
like image 137
James Thomas Avatar answered Nov 09 '22 02:11

James Thomas


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; }
like image 40
Neville Nazerane Avatar answered Nov 09 '22 00:11

Neville Nazerane


The callback methods work, but are still fairly limited, the approach I took was to use "Mesaging Center" that has been cloned from Xamarin.Forms...

https://github.com/aksoftware98/blazor-utilities

https://www.nuget.org/packages/AKSoftware.Blazor.Utilities/

https://youtu.be/HdEJ4GD9hwM

It's very simple, flexible, and behaves much more like a pubsub messaging system across components interanally which has many benefits.

As a result you can "broadcast" events to individual or multiple components regardless of nesting state and location - super flexible and useful. Taken from their docs...

Place a using in your _imports.razor

@using AKSoftware.Blazor.Utilities

Then put a subscriber in the MainLayout.razor

public void SubscribeToMessage()
{
    MessagingCenter.Subscribe<Component1, string>(this, "greeting_message", 
(sender, value) => 
    {
    // Do actions against the value 
    // If the value is updating the component make sure to call 
    string greeting = $"Welcome {value}";
    StateHasChanged(); // To update the state of the component 
    });
}

And a publisher in any of the componets you want

public void SendMessage()
{
 string valueToSend = "Hi from Component 1";
 MessagingCenter.Send(this, "greeting_message", valueToSend);
}

You can put subscribers and senders in any combination of components. I've been making a project where realtime date was updating multiple componenets at the same time, this was a great solution that allowed me to put all my hub connetion logic in MainLayout.razor, and then call and respond to that across all compoents as needed, prvented multiple hub connections being created, and works well in tandem with cascading states.

like image 1
user520100 Avatar answered Nov 09 '22 00:11

user520100