Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 462
Hal Heinrich Avatar asked Oct 22 '19 18:10

Hal Heinrich


People also ask

How do you pass multiple parameters to Blazor component?

The easiest way is to use Route parameters instead of QueryString: @page "/navigatetopage/{id:int}/{key}" @code { [Parameter] public int Id{get;set;} [Parameter] public string Key{get;set;} ... }

How do you call one component from another component in Blazor?

In Blazor you can get an instance of a component by creating a component reference. To capture a component reference: Add an @ref attribute to the child component. Define a field with the same type as the child component.

Can Blazor components be nested?

In the Blazor application, a component can also be nested inside another component using the HTML syntax. For example, if you want to nest counter component inside the index component then you need to use <Counter /> within the Index component.


1 Answers

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.

like image 73
Mark Scott Avatar answered Sep 19 '22 07:09

Mark Scott