Skip to content

Support for additional date/time input types in <InputDate> and support for DateOnly/TimeOnly bindings. #34594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
394 changes: 392 additions & 2 deletions src/Components/Components/src/BindConverter.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,174 @@ public static EventCallback<ChangeEventArgs> CreateBinder(
return CreateBinderCore<DateTimeOffset?>(factory, receiver, setter, culture, format, ConvertToNullableDateTimeOffsetWithFormat);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<DateOnly> setter,
DateOnly existingValue,
CultureInfo? culture = null)
{
return CreateBinderCore<DateOnly>(factory, receiver, setter, culture, ConvertToDateOnly);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="format"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<DateOnly> setter,
DateOnly existingValue,
string format,
CultureInfo? culture = null)
{
return CreateBinderCore<DateOnly>(factory, receiver, setter, culture, format, ConvertToDateOnlyWithFormat);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<DateOnly?> setter,
DateOnly? existingValue,
CultureInfo? culture = null)
{
return CreateBinderCore<DateOnly?>(factory, receiver, setter, culture, ConvertToNullableDateOnly);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="format"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<DateOnly?> setter,
DateOnly? existingValue,
string format,
CultureInfo? culture = null)
{
return CreateBinderCore<DateOnly?>(factory, receiver, setter, culture, format, ConvertToNullableDateOnlyWithFormat);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<TimeOnly> setter,
TimeOnly existingValue,
CultureInfo? culture = null)
{
return CreateBinderCore<TimeOnly>(factory, receiver, setter, culture, ConvertToTimeOnly);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="format"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<TimeOnly> setter,
TimeOnly existingValue,
string format,
CultureInfo? culture = null)
{
return CreateBinderCore<TimeOnly>(factory, receiver, setter, culture, format, ConvertToTimeOnlyWithFormat);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<TimeOnly?> setter,
TimeOnly? existingValue,
CultureInfo? culture = null)
{
return CreateBinderCore<TimeOnly?>(factory, receiver, setter, culture, ConvertToNullableTimeOnly);
}

/// <summary>
/// For internal use only.
/// </summary>
/// <param name="factory"></param>
/// <param name="receiver"></param>
/// <param name="setter"></param>
/// <param name="existingValue"></param>
/// <param name="format"></param>
/// <param name="culture"></param>
/// <returns></returns>
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public static EventCallback<ChangeEventArgs> CreateBinder(
this EventCallbackFactory factory,
object receiver,
Action<TimeOnly?> setter,
TimeOnly? existingValue,
string format,
CultureInfo? culture = null)
{
return CreateBinderCore<TimeOnly?>(factory, receiver, setter, culture, format, ConvertToNullableTimeOnlyWithFormat);
}

/// <summary>
/// For internal use only.
/// </summary>
Expand Down
24 changes: 24 additions & 0 deletions src/Components/Components/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,30 @@ Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute.Name.set -> vo
Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute.SupplyParameterFromQueryAttribute() -> void
abstract Microsoft.AspNetCore.Components.ErrorBoundaryBase.OnErrorAsync(System.Exception! exception) -> System.Threading.Tasks.Task!
override Microsoft.AspNetCore.Components.LayoutComponentBase.SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) -> System.Threading.Tasks.Task!
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.DateOnly value, System.Globalization.CultureInfo? culture = null) -> string!
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.DateOnly value, string! format, System.Globalization.CultureInfo? culture = null) -> string!
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.DateOnly? value, System.Globalization.CultureInfo? culture = null) -> string?
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.DateOnly? value, string! format, System.Globalization.CultureInfo? culture = null) -> string?
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.TimeOnly value, System.Globalization.CultureInfo? culture = null) -> string!
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.TimeOnly value, string! format, System.Globalization.CultureInfo? culture = null) -> string!
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.TimeOnly? value, System.Globalization.CultureInfo? culture = null) -> string?
static Microsoft.AspNetCore.Components.BindConverter.FormatValue(System.TimeOnly? value, string! format, System.Globalization.CultureInfo? culture = null) -> string?
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToDateOnly(object? obj, System.Globalization.CultureInfo? culture, out System.DateOnly value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToDateOnly(object? obj, System.Globalization.CultureInfo? culture, string! format, out System.DateOnly value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToNullableDateOnly(object? obj, System.Globalization.CultureInfo? culture, out System.DateOnly? value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToNullableDateOnly(object? obj, System.Globalization.CultureInfo? culture, string! format, out System.DateOnly? value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToNullableTimeOnly(object? obj, System.Globalization.CultureInfo? culture, out System.TimeOnly? value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToNullableTimeOnly(object? obj, System.Globalization.CultureInfo? culture, string! format, out System.TimeOnly? value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToTimeOnly(object? obj, System.Globalization.CultureInfo? culture, out System.TimeOnly value) -> bool
static Microsoft.AspNetCore.Components.BindConverter.TryConvertToTimeOnly(object? obj, System.Globalization.CultureInfo? culture, string! format, out System.TimeOnly value) -> bool
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.DateOnly>! setter, System.DateOnly existingValue, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.DateOnly>! setter, System.DateOnly existingValue, string! format, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.DateOnly?>! setter, System.DateOnly? existingValue, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.DateOnly?>! setter, System.DateOnly? existingValue, string! format, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.TimeOnly>! setter, System.TimeOnly existingValue, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.TimeOnly>! setter, System.TimeOnly existingValue, string! format, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.TimeOnly?>! setter, System.TimeOnly? existingValue, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.EventCallbackFactoryBinderExtensions.CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory! factory, object! receiver, System.Action<System.TimeOnly?>! setter, System.TimeOnly? existingValue, string! format, System.Globalization.CultureInfo? culture = null) -> Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.ChangeEventArgs!>
static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary<string!, object?>! parameters) -> Microsoft.AspNetCore.Components.ParameterView
virtual Microsoft.AspNetCore.Components.NavigationManager.NavigateToCore(string! uri, Microsoft.AspNetCore.Components.NavigationOptions options) -> void
virtual Microsoft.AspNetCore.Components.NavigationManager.NavigateToCore(string! uri, bool forceLoad) -> void
Expand Down
56 changes: 56 additions & 0 deletions src/Components/Components/test/BindConverterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,62 @@ public void FormatValue_DateTime_Format()
Assert.Equal(expected, actual);
}

[Fact]
public void FormatValue_DateOnly()
{
// Arrange
var value = DateOnly.FromDateTime(DateTime.Now);
var expected = value.ToString(CultureInfo.CurrentCulture);

// Act
var actual = BindConverter.FormatValue(value);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void FormatValue_DateOnly_Format()
{
// Arrange
var value = DateOnly.FromDateTime(DateTime.Now);
var expected = value.ToString("MM-yyyy", CultureInfo.InvariantCulture);

// Act
var actual = BindConverter.FormatValue(value, "MM-yyyy", CultureInfo.InvariantCulture);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void FormatValue_TimeOnly()
{
// Arrange
var value = TimeOnly.FromDateTime(DateTime.Now);
var expected = value.ToString(CultureInfo.CurrentCulture);

// Act
var actual = BindConverter.FormatValue(value);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void FormatValue_TimeOnly_Format()
{
// Arrange
var value = TimeOnly.FromDateTime(DateTime.Now);
var expected = value.ToString("HH:mm", CultureInfo.InvariantCulture);

// Act
var actual = BindConverter.FormatValue(value, "HH:mm", CultureInfo.InvariantCulture);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void FormatValue_Enum()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Web.JS/dist/Release/blazor.server.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Components/Web.JS/dist/Release/blazor.webview.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/Components/Web.JS/src/Rendering/Events/EventTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,10 @@ function normalizeTimeBasedValue(element: HTMLInputElement): string {
const type = element.type;
switch (type) {
case 'date':
case 'datetime-local':
case 'month':
return value;
case 'datetime-local':
return value.length === 16 ? value + ':00' : value; // Convert yyyy-MM-ddTHH:mm to yyyy-MM-ddTHH:mm:00
case 'time':
return value.length === 5 ? value + ':00' : value; // Convert hh:mm to hh:mm:00
case 'week':
Expand Down
Loading