Passing method to component
Asked Answered
M

3

24

I have been trying to work out how if its possible and how to pass a method from the main page into a component in Blazor.

I have a simple razor page, which contains a component with a button. I want to pass the onclick method from the razor page to the button in the component

Note: I do not need this method to return anything void is fine. I just need to be able to call a method from the main page in a button on the component. I only added int here as a guess since it was complaining about T

Page

@page "/test"
@using Testing.Client.Model;
@using System.Threading;

<TestMethodPassing ExternalMethod="@btnClick"></TestMethodPassing>

@code {

    public Action<int> btnClick(){ return 1;}

}

Model for component

public class TestingMethodPassingModel : ComponentBase
{
    [Parameter]
    protected Action<int> ExternalMethod { get; set; }
}

component

@inherits TestingMethodPassingModel;
@using testing.Client.Model;
@using System.Threading;


<button class="btn btn-primary" @onclick="@ExternalMethod" autofocus>External button</button>


@code {


    }

Errors

The above code gives me the following error

Gives me No overload for 'btnClick' matches delegate 'Action'

I tried doing type T as well and that failed as Blazor cant for some reason find the reference for type T

Update Note

Working example pieced together from the answers. PassingMethodToComponent

Mourant answered 1/7, 2019 at 7:3 Comment(10)
I don´t know razor so well, but I´m pretty sure an onclick-delegate doesn´t expect an int-argument.Tarmac
I've created your example and it's giving CS1503 Argument 2: cannot convert from 'System.Action<int>' to 'Microsoft.AspNetCore.Components.EventCallback error. And CS0428 Cannot convert method group 'btnClick' to non-delegate type 'object'. Did you intend to invoke the method?.Hoptoad
Your code doesn't really show how/where you want to use the return value.Suffragan
Also return 1; will not compile either - CS0029 Cannot implicitly convert type 'int' to 'System.Action<int>'.Hoptoad
I didn't really attend anything at this point i have been trying to make it work. I dont really need the method to return anything i just need to be able to pass it. Someone on Gitter said to use T and it didnt work so i was grasping at straws assuming it needed a return var. Your right Onclick doesnt need return varMourant
Hi, I just want to clarify something before I answer. You say you have a "razor page" but I see in your code sample you have a @code block, which are only used in Blazor components. So are you trying to pass a method from a Razor Page to a Blazor component? Or between two Blazor components?Tims
@ChrisSainty I am using/learning Blazor under a week here. I am also a back end developer making all this even more confusing. If my terminology is incorrect please feel free to correct me in your answer. I just assumed as the page .razor. I am trying to pass it to a blazor component.Mourant
No worries @DalmTo, I just wanted to make sure I gave you the right information :)Tims
Looking at your working example @DalmTo, there is no need for this code ExternalMethod="@((param) => { btnClick(); })". You can just write ExternalMethod="@btnClick". The param object is never used.Tims
Good point! I just updated it with your answer as well.Mourant
T
39

Here is an example of passing a method from a parent to a child and the child invoking it. As you don't require a return value I'm just using Action rather than Action<T>.

There are many ways you can make this code more compact, but I've gone for a more verbose example to hopefully show what's happening a bit better.

Parent Component:

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<Child ParentMethod="@SayHello" />

@code {

    private void SayHello()
    {
        Console.WriteLine("Hello!");
    }

}

Child Component:

<h3>Child</h3>

<button @onclick="@InvokeParentMethod">Click Me!</button>

@code {

[Parameter] public Action ParentMethod { get; set; }

private void InvokeParentMethod()
{
    ParentMethod?.Invoke();
}

}
Tims answered 1/7, 2019 at 7:57 Comment(4)
I had to set things public for it to work. But thanks i like this optionMourant
how to send params to SayHello function from child ?Libration
for an async function just pass Task instead.Antimagnetic
delegate does not take 1 parameterLandahl
S
11

This is because the Click event of btnClick isn't of the type Action<int> but actually EventCallback<TIn>. So change you'll need to change a few things around.

change ExternalMethod to

[Parameter]
protected EventCallback<int> ExternalMethod {get; set;}

and change the btnClick to

public void btnClick(int param) { /* code */ }
// and then set the razor to
<TestMethodPassing ExternalMethod="@btnClick"></TestMethodPassing>

// Or do it with a lambda in the razor

<TestMethodPassing ExternalMethod="@((param) => {/* code */ })"></TestMethodPassing>

There is a GitHub issue tracking the new Event Handling and Binding here

Sandlin answered 1/7, 2019 at 7:8 Comment(7)
Correct. But adding an InternalMethod() as intermediate between onClick and the parameter might fit the requirements better.Suffragan
I used the void option: cannot convert from 'System.Action<object, System.EventArgs>' to 'Microsoft.AspNetCore.Components.EventCallback'Mourant
@DaImTo I just rewrote my questionSandlin
So there no way to pass a method other then doing it inline?Mourant
See @chris-sainty 's answer, this will fit your needs betterAlmanac
@DaImTo as far as I see, it should be possible. I just update my answerSandlin
It works but you missed the call to the method: @((param) => { btnClick(); })Mourant
O
6

This should work:

Page:

<TestMethodPassing ExternalMethod="@btnClick"></TestMethodPassing>
<label>@something</label>

@code {

    string something = "1";

    void btnClick()
    {
        something = "11";
    }
}

TestingMethodPassingModel:

[Parameter]
protected Action ExternalMethod { get; set; }

Component:

<button class="btn btn-primary" @onclick="@ExternalMethod" autofocus>External button</button>

For your example (with Action<int>):

Page:

<TestMethodPassing ExternalMethod="@btnClick"></TestMethodPassing>

@code {

    void btnClick(int arg)
    {

    }
}

TestingMethodPassingModel:

[Parameter]
protected Action<int> ExternalMethod { get; set; }

Component:

<button class="btn btn-primary" @onclick="@ClickHandler" autofocus>External button</button>

@code {
    void ClickHandler()
    {
        ExternalMethod.Invoke(10);
    }
}
Omit answered 1/7, 2019 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.