Ryan Buening
Ryan Buening

Reputation: 1670

Custom Blazor DateTime using inherits InputBase<DateTime> with ValidationMessage

I have the following custom date input:

CustomDateInput.razor

<input type="date"
         class="@CssClass"
         @bind=CurrentValue
         @attributes=AdditionalAttributes />

@if (ValidationFor is not null)
{
    <ValidationMessage For="@ValidationFor" />
}

@using System.Linq.Expressions
@inherits InputBase<DateTime?>

@code {
    [Parameter] public Expression<Func<DateTime>>? ValidationFor { get; set; }

    protected override bool TryParseValueFromString(string? value, out DateTime? result, out string validationErrorMessage)
    {
        result = CurrentValue;
        validationErrorMessage = "";
        return true;
    }
}

FooPage.razor

<CustomInputDate @bind-Value="FooDate" ValidationFor="() => FooDate"></CustomInputDate>

FooPage.razor.cs

public DateTime? FooDate { get; set; }

However, I get errors:

image

How can I modify my CustomDateInput to allow for a Validation parameter to show a ValidationMessage?

Upvotes: 1

Views: 1279

Answers (2)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30485

The component. I've lifted the BuildRenderTree code from InputDate and added in the ValidationMessage component. You need to do it this way as I don't know a way to do the For binding in Razor. I've tied the For directly into the ValueExpression property of InputBase. You'll probably need to add a bit of formatting/css to prettify it.

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Rendering;
using System;

namespace Blazor.Starter.Components.TestComponents
{
    public class CustomDate : InputDate<DateTime?>
    {

        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.OpenElement(0, "input");
            builder.AddMultipleAttributes(1, AdditionalAttributes);
            builder.AddAttribute(2, "type", "date");
            builder.AddAttribute(3, "class", CssClass);
            builder.AddAttribute(4, "value", BindConverter.FormatValue(CurrentValueAsString));
            builder.AddAttribute(5, "onchange", EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValueAsString = __value, CurrentValueAsString));
            builder.CloseElement();
            builder.OpenComponent<ValidationMessage<DateTime?>>(6);
            builder.AddAttribute(7, "For", this.ValueExpression);
            builder.CloseComponent();
        }
    }
}

And a demo page. There's a button to manually set an error message in the validationMessageStore.

@page "/editortest"

<h3>EditorTest</h3>
    <EditForm EditContext="editContext">
        <div>
            <CustomDate @bind-Value="model.Date"></CustomDate>
        </div>
    </EditForm>
<div class="m-3 p-3"><input @bind-value="_errormessage"><button class="btn btn-dark ms-2" @onclick="SetError">Set Error</button></div>


@code {
    private dataModel model { get; set; } = new dataModel();
    private EditContext editContext;
    private string _errormessage { get; set; } = "Error in date";

    protected override Task OnInitializedAsync()
    {
        this.editContext = new EditContext(model);
        return base.OnInitializedAsync();
    }

    private void SetError( MouseEventArgs e)
    {
        var validationMessageStore = new ValidationMessageStore(this.editContext);
        validationMessageStore.Clear();
        var fi = new FieldIdentifier(this.model, "Date");
        validationMessageStore.Add(fi, _errormessage);
    }

    public class dataModel
    {
        public string Email { get; set; }
        public DateTime? Date { get; set; }
    }

}

Upvotes: 2

Nb777
Nb777

Reputation: 2032

I have different way to reach the same result, you can try it!:

[Parameter] public bool ShowError { get; set; } = false;

<input type="date"
     class="@CssClass"
     @bind=CurrentValue
     @attributes=AdditionalAttributes @onfocus="@(() => ShowError =true)"/>
@if(ShoError)
  {
     foreach(var msg in EditCotext.GetValidationMessages(FieldIdententifier))
     {
       <div class="alidation-message">@msg</div>
     }
  }

you need aslo to keep you code TryParseValueFromString

Upvotes: 0

Related Questions