| File: Forms\InputDate.cs | Web Access |
| Project: src\aspnetcore\src\Components\Web\src\Microsoft.AspNetCore.Components.Web.csproj (Microsoft.AspNetCore.Components.Web) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.AspNetCore.Components.Rendering; namespace Microsoft.AspNetCore.Components.Forms; /// <summary> /// An input component for editing date values. /// The supported types for the date value are: /// <list type="bullet"> /// <item><description><see cref="DateTime"/></description></item> /// <item><description><see cref="DateTimeOffset"/></description></item> /// <item><description><see cref="DateOnly"/></description></item> /// <item><description><see cref="TimeOnly"/></description></item> /// </list> /// </summary> public class InputDate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue> : InputBase<TValue> { private const string DateFormat = "yyyy-MM-dd"; // Compatible with HTML 'date' inputs private const string DateTimeLocalFormat = "yyyy-MM-ddTHH:mm:ss"; // Compatible with HTML 'datetime-local' inputs private const string MonthFormat = "yyyy-MM"; // Compatible with HTML 'month' inputs private const string TimeFormat = "HH:mm:ss"; // Compatible with HTML 'time' inputs private string _typeAttributeValue = default!; private string _format = default!; private string _parsingErrorMessage = default!; /// <summary> /// Gets or sets the type of HTML input to be rendered. /// </summary> [Parameter] public InputDateType Type { get; set; } = InputDateType.Date; /// <summary> /// Gets or sets the error message used when displaying an a parsing error. /// </summary> [Parameter] public string ParsingErrorMessage { get; set; } = string.Empty; /// <summary> /// Gets or sets the associated <see cref="ElementReference"/>. /// <para> /// May be <see langword="null"/> if accessed before the component is rendered. /// </para> /// </summary> [DisallowNull] public ElementReference? Element { get; protected set; } /// <summary> /// Constructs an instance of <see cref="InputDate{TValue}"/> /// </summary> public InputDate() { var type = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue); if (type != typeof(DateTime) && type != typeof(DateTimeOffset) && type != typeof(DateOnly) && type != typeof(TimeOnly)) { throw new InvalidOperationException($"Unsupported {GetType()} type param '{type}'."); } } /// <inheritdoc /> protected override void OnParametersSet() { (_typeAttributeValue, _format, var formatDescription) = Type switch { InputDateType.Date => ("date", DateFormat, "date"), InputDateType.DateTimeLocal => ("datetime-local", DateTimeLocalFormat, "date and time"), InputDateType.Month => ("month", MonthFormat, "year and month"), InputDateType.Time => ("time", TimeFormat, "time"), _ => throw new InvalidOperationException($"Unsupported {nameof(InputDateType)} '{Type}'.") }; _parsingErrorMessage = string.IsNullOrEmpty(ParsingErrorMessage) ? $"The {{0}} field must be a {formatDescription}." : ParsingErrorMessage; } /// <inheritdoc /> protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenElement(0, "input"); builder.AddMultipleAttributes(1, AdditionalAttributes); builder.AddAttribute(2, "type", _typeAttributeValue); builder.AddAttributeIfNotNullOrEmpty(3, "id", IdAttributeValue); builder.AddAttributeIfNotNullOrEmpty(4, "name", NameAttributeValue); builder.AddAttribute(5, "class", CssClass); builder.AddAttribute(6, "value", CurrentValueAsString); builder.AddAttribute(7, "onchange", EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)); builder.SetUpdatesAttributeName("value"); builder.AddElementReferenceCapture(8, __inputReference => Element = __inputReference); builder.CloseElement(); } /// <inheritdoc /> protected override string FormatValueAsString(TValue? value) => value switch { DateTime dateTimeValue => BindConverter.FormatValue(dateTimeValue, _format, CultureInfo.InvariantCulture), DateTimeOffset dateTimeOffsetValue => BindConverter.FormatValue(dateTimeOffsetValue, _format, CultureInfo.InvariantCulture), DateOnly dateOnlyValue => BindConverter.FormatValue(dateOnlyValue, _format, CultureInfo.InvariantCulture), TimeOnly timeOnlyValue => BindConverter.FormatValue(timeOnlyValue, _format, CultureInfo.InvariantCulture), _ => string.Empty, // Handles null for Nullable<DateTime>, etc. }; /// <inheritdoc /> protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out TValue result, [NotNullWhen(false)] out string? validationErrorMessage) { if (BindConverter.TryConvertTo(value, CultureInfo.InvariantCulture, out result)) { Debug.Assert(result != null); validationErrorMessage = null; return true; } else { validationErrorMessage = string.Format(CultureInfo.InvariantCulture, _parsingErrorMessage, DisplayName ?? FieldIdentifier.FieldName); return false; } } }