blazormudblazor

Blazor (MudBlazor) : onclick event to trigger action in sibling component


I'm just starting to use Blazor in anger, in particular the use of MudBlazor - and I just can't seem to get my head around triggering an action in a sibling component.

At the moment, I've the following components :

<MudLayout>

    <MudAppBar Elevation="1">
        <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e)=> HandleClick(e))" />
        <MudSpacer />
        <MudIconButton Icon="@Icons.Material.Filled.MoreVert" Color="Color.Inherit" Edge="Edge.End" />
    </MudAppBar>
    
    <NavMenu></NavMenu>
    
    <MudMainContent>
        @Body
    </MudMainContent>

</MudLayout>


@code {

    public void HandleClick(MouseEventArgs e){
        // How to trigger NavMenu action here?
    }
}

The aim is for the MudAppBar to trigger the navigation menu's appearance when they click the button.

I've looked at a few things to do this, such as EventCallbacks, Cascading Parameters etc., but all examples seem to be for parent/child relationships - whereas this is sibling-based.

The NavMenu is just a Razor component with the MudNavMenu within it - with visibility toggled via the bind-Open attribute as per the examples.

I'm missing something very simple I'm sure - but I'm just going around in circles with various approaches.

If anyone could offer some pointers that would be much appreciated.

Here's the NavBar component markup for reference:

<MudDrawer @bind-Open="_drawerOpen" Elevation="2">
    <MudDrawerHeader>
        <MudText Typo="Typo.h5" Class="mt-1">Application</MudText>
    </MudDrawerHeader>

    <MudDrawerContainer>

        <MudNavMenu Class="mud-width-full">

            <MudDivider Class="my-2" />
            <MudNavLink Href="/dashboard" Icon="@Icons.Filled.Dashboard">Dashboard</MudNavLink>
            <MudNavGroup Title="Level 0" Icon="@Icons.Filled.Settings" Expanded="false">
                <MudNavGroup Title="Level 1" Icon="@Icons.Filled.AdminPanelSettings" Expanded="false">
                    <MudNavGroup Title="Level 2" Icon="@Icons.Filled.People" Expanded="false">
                        <MudNavGroup Title="Level 3" Icon="@Icons.Filled.Lock" Expanded="false">
                            <MudNavLink Href="/delete" Icon="@Icons.Filled.DeleteForever">Delete Password</MudNavLink>
                        </MudNavGroup>
                    </MudNavGroup>
                </MudNavGroup>
            </MudNavGroup>
            <MudNavLink Href="/billing" Icon="@Icons.Filled.Receipt">Billing</MudNavLink>
        </MudNavMenu>
    </MudDrawerContainer>


</MudDrawer>



@code {

    bool _drawerOpen = true;

    public void ToggleMenu()
    {
        _drawerOpen = !_drawerOpen;
    }

}

Quick update:

I tried adding the following to my NavMenu component:

    [Parameter]
    public bool IsOpen { get; set; }

    [Parameter]
    public EventCallback<bool> IsOpenChanged{ get; set; }

Then employed it to the MudDrawer:

<MudDrawer @bind-Open="IsOpen" 

Then within the MainLayout, set it in the markup:

<NavMenu @bind-IsOpen="_drawerOpen"></NavMenu>

Then adjusted the OnClick of the button to call the following (still within the MainLayout):

    bool _drawerOpen = true;

    public void ToggleMenu()
    {
        _drawerOpen = !_drawerOpen;
    }

This works. However it feels a bit smelly, and I'm not convinced I'm approaching this in the right way. Ideally I'd want the NavMenu to manage its own state, and for the button in the MainLayout to simply trigger an event that the NavMenu is listening for.

At least it works. Obviously I could just bung the MudNavMenu/Drawer into the same layout and not have this problem - but I want to get basic component communication nailed down and this seems a very simple thing to get working.


Solution

  • One solution is to get the NavMenu component reference using the @ref attribute and use the reference to trigger some action:

    <MudLayout>
    
        <MudAppBar Elevation="1">
            <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e)=> HandleClick(e))" />
            <MudSpacer />
            <MudIconButton Icon="@Icons.Material.Filled.MoreVert" Color="Color.Inherit" Edge="Edge.End" />
        </MudAppBar>
        
        <NavMenu @ref="_navMenuRef"></NavMenu>
        
        <MudMainContent>
            @Body
        </MudMainContent>
    
    </MudLayout>
    
    
    @code {
        private NavMenu _navMenuRef;
    
        public void HandleClick(MouseEventArgs e)
        {
            // call ToggleMenu or any other method
            _navMenuRef.ToggleMenu();
        }
    }