Estoy creando una aplicación del lado del servidor blazor y tengo problemas para vincular un valor entre dos componentes personalizados.

He analizado diferentes ejemplos de cómo se supone que funciona el enlace o @bind, pero no puedo averiguar qué información actualizada sobre este asunto.

Dado un usuario de clase de modelo:

public class User
    {
        [Mapping(ColumnName = "short_id")]
        public string ShortId { get; set; }

        public User()
        {

        }
    }

Quiero crear un formulario que muestre todas las propiedades de este usuario y las tenga en una entrada para poder editarlo y, al final, guardarlo en una base de datos.

Mi formulario (componente principal) se ve así:

<div class="edit-user-form">
    <AnimatedUserInput TbText="@User.ShortId" Placeholder="MHTEE Id"/>
    <button class="btn btn-secondary" @onclick="Hide" style="{display:inline-block;}">Back</button>
    <button class="btn btn-primary" @onclick="SaveUser" style="{display:inline-block;}">Save</button>
</div>
@code {
    [Parameter] public vUser User { get; set; }

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

    bool _error = false;

    void SaveUser()
    {
        ValidateUserData();
    }

    void ValidateUserData()
    {
        _error = string.IsNullOrWhiteSpace(User.ShortId);
    }
}

Donde AnimatedUserInput es un componente personalizado que tiene este aspecto:

<div class="edit-area @FocusClass @WiggleClass">
    <input type="text" @bind="@TbText" />
    <span data-placeholder="@Placeholder"></span>
</div>
@code {
    [Parameter]
    public string TbText { get; set; }

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

Ahora, en el cuadro de texto de entrada, veo correctamente el ShortId del objeto User en mi componente principal.

Sin embargo, si cambio el texto en la entrada y hago clic en el botón Save que activa el método ValidateUserData y me permite ver el objeto User actual, veo que no se han realizado cambios. en la propiedad User.ShortId real pero solo en la entrada.

¿Hay alguna forma de enlazarlo para que los cambios en la entrada se apliquen automáticamente a la propiedad enlazada?

Tengo varias de estas propiedades que deben mostrarse en el formulario, por lo que no quiero conectar un evento OnChanged personalizado para cada una de esas propiedades.

9
Drew Fyre 2 oct. 2019 a las 10:14

2 respuestas

La mejor respuesta

Bueno, para cualquiera que se encuentre con esto. Intenté un poco más y encontré una solución. Entonces, a mi componente de entrada personalizado AnimatedUserInput agregué un EventCallback al que llamo cada vez que se actualiza el valor en la entrada:

@code {

    [Parameter]
    public string TbText
    {
        get => _tbText;
        set
        {
            if (_tbText == value) return;

            _tbText = value;
            TbTextChanged.InvokeAsync(value);
        }
    }

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

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

    private string _tbText;
}

Y el enlace en mi componente principal se ve así:

<div class="edit-user-form">
    <AnimatedUserInput @bind-TbText="@User.ShortId" Placeholder="MHTEE Id"/>
    <AnimatedUserInput @bind-TbText="@User.FirstName" Placeholder="First name" />
    <AnimatedUserInput @bind-TbText="@User.LastName" Placeholder="Last name" />
    <AnimatedUserInput @bind-TbText="@User.UserName" Placeholder="Username" />
    <AnimatedUserInput @bind-TbText="@User.StaffType" Placeholder="Staff type" />
    <AnimatedUserInput @bind-TbText="@User.Token" Placeholder="Token" />
    <button class="btn btn-secondary" @onclick="Hide" style="{display:inline-block;}">Back</button>
    <button class="btn btn-primary" @onclick="SaveUser" style="{display:inline-block;}">Save</button>
</div>

@code {
    [Parameter] public vUser User { get; set; }
}

De esta manera, blazor puede unir correctamente los valores y los actualiza desde ambos lados de la forma en que esperaría que se unieran.

17
Drew Fyre 7 oct. 2019 a las 07:32

Así es como logré la unión bidireccional

Componente principal

<LabelledField Class=""
   Label="Label value"
   DateValue="@Model.Value"
   OnDateChange="@((e) => Model.Value = e )"
   Type="InputType.date" />

Componente hijo

<div class="@Class">
<div class="ft-07 mb-03 field-label @LabelClass">@Label</div>
@switch (Type)
{
    case InputType.constant:
        <div class="label-field-value @ValueClass">@Value</div>
        break;
    case InputType.text:
        <input class="form-control input @ValueClass"
               type="text"
               @bind="Value" />

        break;
    case InputType.date:
        <input class="form-control input @ValueClass"
               type="date"
               @bind="DateValue" />

        break;
    default:
        break;
}
@code{
private string _tbText;
private DateTime? _tbDate;

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

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

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

[Parameter]
public string Value
{
    get => _tbText;
    set
    {
        if (_tbText == value) return;

        _tbText = value;
        OnTextChange.InvokeAsync(value);
    }
}

[Parameter]
public DateTime? DateValue
{
    get => _tbDate;
    set
    {
        if (_tbDate == value) return;

        _tbDate = value;
        OnDateChange.InvokeAsync(_tbDate);
    }
}

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

[Parameter]
public InputType Type { get; set; } = InputType.constant;

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

[Parameter]
public EventCallback<DateTime?> OnDateChange { get; set; }
}
0
prvn 13 abr. 2021 a las 17:10