Пользовательский компонент Blazor InputText

Я пытаюсь создать «составной» компонент ввода текста Blazor.

Я хотел бы объединить

  • заголовок/метка для текстового поля ввода
  • фактическое текстовое поле ввода
  • счетчик, показывающий, сколько символов определенной максимальной длины уже использовано

Пока что я создал что-то вроде этого (немного упрощенно):

MyInputText.razor:

<div class = "row">
    <div class = "col-md-3">
        <label>@Title</label>
    </div>
    <div class = "col-md-8">
        <InputText class = "form-control" name = "textbox" @bind-Value = "Value" @oninput = "TextInputEvent" />
        <ValidationMessage For = "() => Value" />
    </div>
    <div class = "col-md-1">
        <label>@CurrentChars / @MaxChars</label>
    </div>
</div>

MyInputText.razor.cs:

public partial class MyTextInput
{
    [Parameter]
    [EditorRequired]
    public string Title { get; set; } = string.Empty;

    [Parameter]
    [EditorRequired]
    public string Value { get; set; } = string.Empty;

    [Parameter]
    [EditorRequired]
    public int MaxChars { get; set; } = 255;

    public int CurrentChars { get; set; }

    private void TextInputEvent()
    {
        CurrentChars = Value.Length;
    }
}

Кажется, почти работает, но:

  • Кажется, он всегда «на шаг позади» — поэтому, если у меня четыре символа и я ввожу пятый — для «CurrentChars» установлено значение 4. Кажется, он смотрит на «старое» содержимое Value — перед символом, который я только что набрал зарегистрирован

  • Кажется, это работает только для первого символа, который я набираю - любые последующие символы, похоже, больше не запускают обработчик TextInputEvent...

Есть идеи, чего мне здесь не хватает?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
90
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это потому, что bind-value обновляет значение после срабатывания on-input. Пробовали ли вы сделать это одновременно:

<div class = "row">
  <div class = "col-md-3">
        <label>@Title</label>
    </div>
    <div class = "col-md-8">
        <InputText class = "form-control" name = "textbox" value = "@Value" ValueChanged = "OnValueChanged" ValueExpression = "() => Value" />
        <ValidationMessage For = "() => Value" />
    </div>
    <div class = "col-md-1">
        <label>@CurrentChars / @MaxChars</label>
    </div>
</div>

public partial class MyTextInput : ComponentBase
{
    [Parameter]
    [EditorRequired]
    public string Title { get; set; } = string.Empty;

    [Parameter]
    [EditorRequired]
    public string Value { get; set; } = string.Empty;

    [Parameter]
    [EditorRequired]
    public int MaxChars { get; set; } = 255;

    public int CurrentChars { get; set; }

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

    private async Task OnValueChanged(ChangeEventArgs e)
    {
        Value = e.Value?.ToString() ?? string.Empty;
        CurrentChars = Value.Length;
        await ValueChanged.InvokeAsync(Value);
    }
}

исправили это. пожалуйста, посмотрите.

decius 24.06.2024 11:59

Я думаю, что значение связывается только после того, как ввод потерял фокус. Вам не нужны другие изменения. просто используйте:

    private void TextInputEvent(ChangeEventArgs args)
    {
        CurrentChars = args.Value.ToString().Length;  
    }

Да, спасибо - работает как шарм!

marc_s 24.06.2024 12:08

Решает ли это фундаментальную проблему привязки - @bind-Value = "Value"? Внутри компонента это установка параметра, которую не следует делать. Как обновляется модель родительской формы? См. — Learn.microsoft.com/en-us/aspnet/core/blazor/comComponents/…

MrC aka Shaun Curtis 24.06.2024 12:18
Ответ принят как подходящий

Другие ответы касаются необходимости ручной привязки в вашем решении.

Альтернативой является наследование напрямую от InputText.

Ключевым преимуществом этого является то, что вам не нужно изобретать велосипед. Вы используете все встроенные функции InputBase с помощью EditContext и проверки.

В примере я добавил опцию UpdateOnInput, так как вы, вероятно, в какой-то момент воспользуетесь ею.

@inherits InputText

<div class = "row">
    <div class = "col-md-3">
        <label>@Title</label>
    </div>
    <div class = "col-md-8">
            <input class = "@this.CssClass"
                   type = "text"
                   value = "@this.CurrentValueAsString"
                   @oninput = "this.OnInput"
                   @onchange = "this.OnChange"
                   @attributes=this.AdditionalAttributes
                   @ref=this.Element />
        <ValidationMessage For = "() => Value" />
    </div>
    <div class = "col-md-1">
        <label>@CurrentChars / @MaxChars</label>
    </div>
</div>
@code {
    [Parameter, EditorRequired] public string Title { get; set; } = string.Empty;
    [Parameter, EditorRequired] public int MaxChars { get; set; } = 255;
    [Parameter] public bool UpdateOnInput { get; set; }

    public int CurrentChars { get; set; }

    private void OnInput(ChangeEventArgs e)
    {
        CurrentChars = e?.Value?.ToString()?.Length ?? 0;
        if (UpdateOnInput)
            CurrentValueAsString = e?.Value?.ToString() ?? null;

    }

    private void OnChange(ChangeEventArgs e)
    {
        if (!UpdateOnInput)
            CurrentValueAsString = e?.Value?.ToString() ?? null;
    }
}

Демо:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<EditForm Model = "_model">
    <MyInputText class = "form-control" @bind-Value = "_model.Value" MaxChars = "10" Title = "My Value" />
    <MyInputText class = "form-control" @bind-Value = "_model.Value2" UpdateOnInput MaxChars = "10" Title = "My Value" />
</EditForm>

<div class = "bg-dark text-white m-2 p-2">
    <pre>Value: @_model.Value</pre>
    <pre>Value2: @_model.Value2</pre>
</div>

@code{
    private Model _model = new();


    public class Model
    {
        public string? Value { get; set; }
        public string? Value2 { get; set; }
    }
}

Хорошо, хорошая попытка, спасибо.

marc_s 24.06.2024 12:09

Другие вопросы по теме