3
votes

I am trying to two-way bind a text area inside a child component in Blazor and I just can't figure it out.

Parent

@page "/test"

<h3>Parent Component</h3>
<input type="text" @bind="mydata" />

<TWBTextArea @bind-ChildData=@mydata></TWBTextArea>

@code {
    public string mydata = "test";
}

Child

<h4>Child Component</h4>

<textarea @bind=@ChildData></textarea>

@code {
    [Parameter] public string ChildData { get; set; }

    [Parameter]
    public EventCallback<string> ChildDataChanged { get; set; }
}

When I update from the parent component, the child textarea updates, but when I update the child text area, the parent is not updated.

Additional note : If I change the value being passed from a string to an object with a string property and I pass that object to the Child Component, two way binding DOES work but only after an update to the parent component.

Thanks in advance for any help!

1

1 Answers

5
votes

Important: You should not bind to components' parameters as it may have side-effects on your app. Read this post by Steve Sanderson

Note that I define a local variable, named data, into which I assign the ChildData parameter property's value from the OnParametersSet method. That is done, as I've said before, in order to refrain from binding to a component's parameter.

Since we are creating a two-way data-binding, the value attribute of the textarea element is bound to the variable data. The flow of data is from the variable to the element. We also need to create an event handler, named here HandleOnChange, whose role is to update the local variable data, as well as to invoke the EventCallback 'delegate', passing the new value stored in the data variable. This value is gladly received in the parent component's mydata field, after which, a re-rendering occurs to reflect the new changes.

Note that I'm using the input event, instead of the change event, to make life easier and more interesting.

Child component

<h4>Child Component</h4>

<textarea @oninput="HandleOnChange">@data</textarea>

@code {

    private string data;

    [Parameter] public string ChildData { get; set; }

    [Parameter]
    public EventCallback<string> ChildDataChanged { get; set; }

    private async Task HandleOnChange(ChangeEventArgs args)
    {
        data = args.Value.ToString();

        await ChildDataChanged.InvokeAsync(data);
    }

    protected override void OnParametersSet()
    {
        data = ChildData;

        base.OnParametersSet();
    }
}

Usage

@page "/test"

<h3>Parent Component</h3>
<input type="text" @bind="mydata" @bind:event="oninput" />

<ChildComponent @bind-ChildData="mydata" />

@code {
    private string mydata = "test";
}