컴포넌트의 컨트롤과 메인페이지의 프로퍼티 바인딩 관련

안녕하세요.
Blazor를 이용하여 custom component를 작성중에 있습니다.
기능은 Select 박스와 Input 박스가 합쳐진 컨트롤를 만들고 있는데요.
메인페이지에서 배열데이터를 넘겨주고 해당 배열 데이터를 Select박스에 노출시키고 선택하면 선택된 값을 그리고 직접입력이라는 값을 선택하면 그 옆의 텍스트박스가 활성화되면서 직접 입력한 값을 사용하는 컨트롤입니다.

메인페이지에서 이 컴포넌트를 불러와서 사용하면 문제가 단방향(?) 바인딩만
이루어집니다. 그러니까 컴포넌트와 메인페이지의 프로퍼티를 바인딩 시켜서
컴포넌트안의 값이 바뀌거나 메인페이지의 프로퍼티가 바뀌어도 컴포넌트의 값이 같이 바뀌게끔 양방향으로 작성하고 싶습니다.

현재 증상은 컴포넌트에서 값을 바꾸면 메인페이지에 연결된 프로퍼티는 값이 잘 변경 됩니다.

반대로 메인페이지에 컨트롤과 바인딩된 프로퍼티를 바꿔도 컴포넌트의 값은 바뀌지 않습니다.

뭔가 메인페이지의 프로퍼티가 변경되면 이벤트를 통해서 컴포넌트쪽으로도 값이 변경됐으니 너도 적용해라 라는 부분이 필요할 것 같은데요. 이 부분을 어떻게 적용해야 할지 모르겠습니다.

컴포넌트 소스코드---------------------------------------------------------------------------

<Select Size="Size.Small" TValue="int" SelectedValue="@value" SelectedValueChanged="OnChanged">
    <SelectItem Value=0>직접입력</SelectItem>
    @foreach (var item in Data)
    {
        <SelectItem Value=item>@item</SelectItem>
    }
</Select>
<NumericEdit TValue="int" Size="Size.Small" ReadOnly=@isReadOnly Value="@selectedValue" ValueChanged="@OnValueChanged" />
@code 
{
    [Parameter] public int[] Data { get; set; }
    [Parameter] public EventCallback<int> OnSelectedValueChanged { get; set; }
    private int selectedValue { get; set; }
    private int value;
    private bool isReadOnly = false;

    private Task OnChanged(int val)
    {
        if (val.Equals(0))
        {
            isReadOnly = false;
        }
        else
        {
            isReadOnly = true;
            value = val;
            selectedValue = val;
        }

        OnSelectedValueChanged.InvokeAsync(selectedValue);
        return Task.CompletedTask;
    }

    private async Task OnValueChanged(int val)
    {
        selectedValue = val;
        await OnSelectedValueChanged.InvokeAsync(selectedValue);
    }
}

메인페이지의 해당 컴포는트코드와 프로퍼티 소스코드--------------------

<InputSelectBox Data="@(new[] {1,2,4,8,12, 16, 20, 24, 32 })" 
OnSelectedValueChanged="@( x => {Cpu = x;})" ></InputSelectBox>

@code
{
       public int Cpu { get; set; }
}

----===================================================
참고로 Blazorise라는 라이브러리를 사용했습니다.

조언 부탁드립니다.

감사합니다. 코드로 표시

2개의 좋아요

실행 가능한 코드를 GitHub로 공유해 주시면 도움을 드릴 수 있습니다.

일단 @bind-로 양방향 바인딩이 되어있지 않아 생기는 문제로 보입니다.

2개의 좋아요

넵 제가 코드 좀 정리하고 다시 댓글 달겠습니다.

2개의 좋아요

GitHub - aanicall/BlazorConponentTest: BlazorConponentTest 에 소스 올렸습니다.

좌측메뉴의 5번째 component Test를 누르시면 보실 수 있습니다.
(현재 사이트 시작하면 바로 뜨게 "/"로 페이지 잡아놨습니다.)

불필요한 blazorise 라이브러리가 들어있어 깃헙 소스에서는 걷어냈습니다.

감사합니다.

1개의 좋아요

먼저 양방향 바인딩이 되도록 InputSelectBox.razor의 파라미터를 변경합니다.

...
    [Parameter] public int SelectedValue { get; set; }
    [Parameter] public EventCallback<int> SelectedValueChanged { get; set;  }
...

이후 호출하는 쪽에서 SelectedValue를 바인딩 합니다.

컴포넌트 : <InputSelectBox Data="@(new[] {1,2,4,8,12, 16, 20, 24, 32 })" @bind-SelectedValue="@ProductCpu"></InputSelectBox>

바인딩 된 값이 변경되었을 때 input의 값이 변경되도록 바인딩 합니다.

<input type="text" @bind-value="SelectedValue" @oninput="OnTextChanged" readonly="@isReadOnly" style="@(isReadOnly ? "background-color:darkgray;" : "")" />

| ComponentTest.razor

@page "/"; 

<h3>ComponentTest</h3>

* 유효성 검사 부분이 빠져 현재는 숫자만 입력해 주시기 바랍니다.
<br /><br />

컴포넌트 : <InputSelectBox Data="@(new[] {1,2,4,8,12, 16, 20, 24, 32 })" @bind-SelectedValue="@ProductCpu"></InputSelectBox>

<br /><br />

메인 프로퍼티 값 : <input type="text" @bind="ProductCpu" />

<br/><br />

1. 컴포넌트의 select 박스의 숫자를 선택하거나 '직접입력'으로 하고 옆의 text박스에 값을 입력하면 컴포넌트의 값이 바뀌고
아래의 메인 프로퍼티 값도 같이 바인딩 되어 바뀝니다. 

<br /><br />

2. 반대로 메인프로퍼티 값의 text박스를 바꾸면 컴포넌트의 select박스의 항복에 있는 값이면 항목으로 설정이 되고 text박스의 값은
메인 프로퍼티와 같은 값으로 설정되게 하고자 합니다.

<br /><br />

현재 1번은 동작확인이 되는데 2번을 어떻게 해야 할지 궁금합니다.

@code {
public int ProductCpu { get; set; }
}

| InputSelectBox.razor

<select @onchange="OnSelectChanged">
    <option value=0>직접입력</option>
    @foreach (var item in Data)
    {
        <option value=@item>@item</option>
    }
</select>
<input type="text" @bind-value="SelectedValue" @oninput="OnTextChanged" readonly="@isReadOnly" style="@(isReadOnly ? "background-color:darkgray;" : "")" />

@code 
{
    [Parameter] public int[] Data { get; set; }
    [Parameter] public int SelectedValue { get; set; }
    [Parameter] public EventCallback<int> SelectedValueChanged { get; set;  }
    private bool isReadOnly = false;

    private Task OnSelectChanged(ChangeEventArgs e)
    {
        if (Convert.ToInt32(e.Value).Equals(0))
        {
            isReadOnly = false;
        }
        else
        {
            isReadOnly = true;
            //value = Convert.ToInt32(e.Value);
            SelectedValue = Convert.ToInt32(e.Value);
        }

        SelectedValueChanged.InvokeAsync(SelectedValue);
        return Task.CompletedTask;
    }

    private async Task OnTextChanged(ChangeEventArgs e)
    {
        SelectedValue = Convert.ToInt32(e.Value);
        await SelectedValueChanged.InvokeAsync(SelectedValue);
    }
}
3개의 좋아요

와 이렇게 신경 써주셔서 너무 감사드립니다.

말씀하신 부분 수정해서 적용하니 잘 되네요.

답변 너무 감사합니다. :grinning:

3개의 좋아요