Custom component doesn't return value when the validation is not successful

Viewed 168

I'm creating a simple custom currency component in Blazor. I inherit from InputBase<string> and implement bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage)

The problem is that i want to return value when the TryParseValueFromString is not successful.

Parent component

 <div class="form-group mb-3">
            <label for="MyInputTextArea">Input currency</label>
            <InputCurrency @bind-Value=FormData.SomeStringCurrency id="MyInputTextArea" class="form-control"/>
            <ValidationMessage For="() => FormData.SomeStringCurrency"></ValidationMessage>
        </div>

Custom component

@using System.Globalization
@inherits InputBase<string>

<input type="string" @attributes=AdditionalAttributes class=@CssClass @bind=CurrentValueAsString />

@code{
private CultureInfo _culture = CultureInfo.CreateSpecificCulture("de");

protected override string FormatValueAsString(string value)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        return string.Empty;
    }

    if (Decimal.TryParse(value, NumberStyles.Currency, _culture, out decimal result))
    {
        return Convert.ToDecimal(value).ToString("N", _culture);
    }
    else
    {
        return value;
    }
}

protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
{
    try
    {
        var decimalValue = ReturnDecimalIfSuccessFul(value);

        result = decimalValue.ToString();
        validationErrorMessage = null;
        return true;
    }
    catch
    {
        validationErrorMessage = "Not a valid currency value.";
        result = value; // here i am assigning the value but it's not returned 
        return false;
    }
}

private decimal? ReturnDecimalIfSuccessFul(string value)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        return null;
    }

    var result = Decimal.Parse(value, NumberStyles.Currency, _culture);
    
    return result;
}

user input

result

what i expect

When the value is not successfully parsed then is not showed to the user. Only the last successfully value is showed, but I expect to always have the value user put in input...

1 Answers

Copy run and test...

InputCurrency.razor

@using System.Globalization
@inherits InputBase<string>

<input type="text" @attributes="AdditionalAttributes" class=@CssClass value="@CurrentValue" 
                                                         @onchange="OnInputValueChanged" />

@code{
    private CultureInfo _culture = CultureInfo.CreateSpecificCulture("de");

    protected async Task OnInputValueChanged(ChangeEventArgs e)
    {
        CurrentValueAsString = e.Value.ToString();
        await Task.CompletedTask;
    }

    protected override string FormatValueAsString(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return string.Empty;
        }

        if (Decimal.TryParse(value, NumberStyles.Currency, _culture, out decimal result))
        {
            return Convert.ToDecimal(value).ToString("N", _culture);
        }
        else
        {
            return value;
        }
    }

    protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
    {
        try
        {
            var decimalValue = ReturnDecimalIfSuccessFul(value);

            result = decimalValue.ToString();
            validationErrorMessage = null;
            return true;
        }
        catch
        {
            validationErrorMessage = "Not a valid currency value.";
            result = value; // here i am assigning the value but it's not returned
            return false;
        }
    }

    private decimal? ReturnDecimalIfSuccessFul(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return null;
        }

        var result = Decimal.Parse(value, NumberStyles.Currency, _culture);

        return result;
    }
}

Index.razor

@page "/"

<EditForm EditContext="@EditContext" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />

    <div class="form-group">
        <label for="name">Name: </label>
        <InputText Id="name" Class="form-control" @bind-Value="@product.Name"></InputText>
        <ValidationMessage For="@(() => product.Name)" />

    </div>

    <div class="form-group">
        <label for="MyInputTextArea">Input currency</label>
        <InputCurrency @bind-Value=product.Price id="MyInputTextArea" class="form-control" />
        <ValidationMessage For="() => product.Price"></ValidationMessage>
    </div>
    <p>
        <button type="submit">Save</button>
    </p>
</EditForm>

@code
    {

    private EditContext EditContext;
    private Product product = new Product();
   

    protected override void OnInitialized()
    {
        EditContext = new EditContext(product);

        base.OnInitialized();
    }


    public async Task HandleValidSubmit()
    {
   
        await Task.Run(() =>
        {
            Console.WriteLine("Saving...");
           
        });

    }

    public class Product
    {
        public string Name { get; set; }
        public string Price { get; set; }
    }
}
Related