Blazor: Pass a function that takes parameters to a component and call it from it
Asked Answered
C

2

6

I'm trying to split my Blazor Server project into components in order to make it more manageable.

I want my component to have a function passed in as a parameter to it. The function takes a string parameter and it is called with different names from the component when a button is clicked.

I've tried some answers I found online but they don't seem to work(Like binding events)

Code

I have a component named ItemMenu.razor and my index page Index.razor.

ItemMenu.razor:


<button @onclick="() => OnClickFunction.Invoke(foo)">foo</button>
<button @onclick="() => OnClickFunction.Invoke(ping)">ping</button>

@code {
    [Parameter] public Action<string> OnClickFunction { get; set; }

    const string foo = "bar";
    const string ping = "pong";
}

Index.razor:

@page "/"

<h1>This is my index page!</h1>

<ItemMenu OnClickFunction="ShowName" /> @*Error: No overload for 'ShowName' matches delegate 'Action'*@

@code {
    public void ShowName(string myName)
    {
        Console.WriteLine(myName);
    }
}


Error

Line 3 in Index.html throws the error No overload for 'ShowName' matches delegate 'Action'

Solution

Turns out I just needed to rename my variable to OnClick instead of OnClickFunction...

Ok @enet pointed out the variable name wasn't the problem. In blazor we should use the EventCallback and not Action.

Turns out the real problem in my case was Visual Studio as I found this solution earlier when looking at other answers. VS decided to show an error on this line even though it compiles and runs fine...

Chondrule answered 30/3, 2021 at 7:41 Comment(1)
Does this answer your question? Passing method to componentHalibut
O
9

Note: The issue is not the naming of the function as you've expressed in your comment to Brian. The issue is that you use the Action delegate, but an Action delegate does not return a value, or rather it returns void. You could have used the Func delegate instead, so that you could invoke your method and return a value. However, the correct way in Blazor is to use the EventCallback struct, which produces the suitable delegate for you. It also has other benefits.

ItemMenu.razor

<button @onclick="() => OnClickFunction.InvokeAsync(foo)">foo</button>
    <button @onclick="() => OnClickFunction.InvokeAsync(ping)">ping</button>
    
    @code {
        [Parameter] public EventCallback<string> OnClickFunction { get; set; }
    
        const string foo = "bar";
        const string ping = "pong";
    }

Index.razor

@page "/"

<h1>This is my index page!</h1>

<ItemMenu OnClick="ShowName" /> @*Error: No overload for 'ShowName' matches delegate 'Action'*@

@code {
    public void ShowName(string myName)
    {
        Console.WriteLine(myName);
    }
}
Overmaster answered 30/3, 2021 at 8:2 Comment(1)
Ok, I see what is happening, the problem all along was in Visual Studio... It complained that there was an error in this line but it compiles and runs fine... I understand now the answer. Thank you!Chondrule
L
2

Your binding was a little bit short ;)

<button @onclick=@(() => OnClick.InvokeAsync("foo"))>foo</button>
<button @onclick=@(() => OnClick.InvokeAsync("ping"))>ping</button>

@code {
    [Parameter]
    public EventCallback<string> OnClick { get; set; }
}
@page "/"

<h1>This is my index page!</h1>

<ItemMenu OnClick="ShowName" /> @*Error: No overload for 'ShowName' matches delegate 'Action'*@

@code {
    public void ShowName(string myName)
    {
        Console.WriteLine(myName);
    }
}
Lucero answered 30/3, 2021 at 7:54 Comment(1)
Ok thank you, turns out I just needed to rename my variable to OnClick instead of OnClickFunctionChondrule

© 2022 - 2024 — McMap. All rights reserved.