Search code examples
razorcomponentsparameter-passingblazorasp.net-core-3.0

How do I pass data between Razor components on the same Blazor page?


I have this Blazor page

@page "/bearoffdata"
@using BlazorBoinq.Components

<h3>Bearoff Data</h3>

<Position_Hex_IdPair />

<PositionData />

@code {

}

with these two Razor components:

@using BlazorBoinq.Data
@using BgBearoffCoreNamespace;
@inject BgBearoffService BoService

<label>Position</label>

<input type="text" spellcheck="false" @bind-value="@PositionText" @bind-value:event="oninput" />

<span> = </span>

<input type="number" step="1" @bind-value="@PositionId" @bind-value:event="oninput" />

<label>Id</label>

@code {

    BgBearoffCore BgBo;

    protected override async Task OnInitializedAsync()
    {
        BgBo = await BoService.GetBgBearoffAsync();
    }

    private Int64 positionId;
    private String positionText;

    protected Int64 PositionId
    {
        get => positionId;
        set
        {
            positionId = value;
            if (positionId > 0 && positionId <= BgBo.MaxId)
            {
                positionText = BgBearoffCore.menOnPointToHexString(BgBo.getMenOnPointFromInvariantId(positionId));
            }
            else
                positionText = "";
        }
    }

    protected String PositionText
    {
        get => positionText;
        set
        {
            positionText = value;
            if (BgBo.IsValidHexPosition(positionText))
                positionId = BgBo.getInvariantIdFromPosition(positionText);
            else
                positionId = 0;
        }
    }
}

and

@using BlazorBoinq.Data
@using BgBearoffCoreNamespace;
@inject BgBearoffService BoService

<button class="btn btn-primary" @onclick="ShowBearoffInfo">Show Data</button>

<br>

<textarea cols="36" rows="36" readonly @bind="@BearoffInfo" />


@code {
    BgBearoffCore BgBo;

    protected override async Task OnInitializedAsync()
    {
        BgBo = await BoService.GetBgBearoffAsync();
    }


    private String bearoffInfo = "";
    public String BearoffInfo
    {
        get => bearoffInfo;
        set { }
    }
    protected void ShowBearoffInfo()
    {
        bearoffInfo = BgBo.getPositionInformationText(86);
    }
}

I want to pass the PositionId of the first component to the second component, so I can replace hard-coded 86 in the last line, with the PositionId parameter.


Solution

  • Here's one possible solution, that might be feasible because you have access to the code for the components you're using.

    There are three steps to this solution:

    1. Define an event callback in your first component.
    2. Define a parameter in your second component.
    3. Define a property in your parent component (your page).

    Step 1: Define an event callback in your first component.

    This will allow you to notify the parent component (your page) when the property changes.

    Declare your PositionId property as a public parameter.

    [Parameter] public int PositionId
    

    You can leave your getters and setters as they are.

    Change your input to this:

    <input type="text" spellcheck="false" @oninput="OnPositionIdChanged" />
    

    Declare an event callback like this:

    [Parameter] public EventCallback<int> PositionIdChanged { get; set; }
    

    Then define a method to handle the change like this:

    private Task OnPositionIdChanged(ChangeEventArgs e)
    {
        PositionId = int.Parse(e.Value.ToString());
        return PositionIdChanged.InvokeAsync(PositionId);
    }
    

    Now, when the value in the input changes, an EventCallback will be raised.

    Step 2: Define a parameter in your second component.

    This will allow you to pass a value into your second component from your parent component (your page).

    Declare a public parameter like this:

    [Parameter] public int APositionId {get; set; }
    

    Step 3: Define a property in your parent component (your page).

    Here, you define a property, get it to update when the value of the property in your first component changes, then supply that value to the parameter in your second component.

    Define a property in your page like so:

    private int SuppliedPosition { get; set; }
    

    Wire it to the change notifier in your first component like so:

    <Position_Hex_IdPair @bind-PositionId="SuppliedPosition"  />
    

    Supply it to the parameter in your second component like so:

    <PositionData APositionId="@SuppliedPosition"/>
    

    I've named each of the additional properties slightly differently so it's hopefully clear which is which.

    That's it! The drawback to this solution is that it requires you to change your components, and to add code to your page.

    There's more information about event callbacks and parameters at the Blazor documentation: Blazor docs.

    Hope this helps.