MudBlazor / MudBlazor

Blazor Component Library based on Material design with an emphasis on ease of use. Mainly written in C# with Javascript kept to a bare minimum it empowers .NET developers to easily debug it if needed.
http://mudblazor.com
MIT License
8.14k stars 1.28k forks source link

New component MudDateTimePicker #1082

Open pedrobulano opened 3 years ago

pedrobulano commented 3 years ago

Hi. Please consider creating a new MudDateTimePicker component. It is available in almost all component libraries. I think that it will be very popular with developers.

Garderoben commented 3 years ago

Agree, i guess we could combine them and switch the view. https://material-ui-pickers.dev/demo/datetime-picker

pedrobulano commented 3 years ago

That would be very nice.

KurtisThorneUK commented 3 years ago

Same requirement here, I've recently been swapping a project from MatBlazor to this one, however I can't remove MatBlazor entirely because it uses MatDateTimePickers.

I like the solution in the link above.

henon commented 3 years ago

Closing this in favor of #1095 where a workaround is posted.

vgb1993 commented 2 years ago

I would like to have a native component that does this. Essentially this is one of the most used fields in an application, and having to search workarounds on Github is suboptimal.

Also this workaround is for a DateTimeOffset, not a simple DateTime. Just saying.

Could you please reconsider opening this issue?

That would be awesome.

henon commented 2 years ago

@vgb1993 do you want to work on such a component?

vgb1993 commented 2 years ago

I have never done something alike, but could do if I understood the steps.

We could first talk about what this component should do?

vgb1993 commented 2 years ago

One way is to add this workaround to the MudBlazor project, the other would be to create a custom picker, like the native html datetime picker.

The first way is easier but it's less efficient in regards of user interaction speed. I managed to incorporate the workaround in my project. So I could do this pretty easy ( I guess ).

The second option sounds more complex. But it would be amazing.

What do you think?

henon commented 2 years ago

I agree, an integrated MudDateTimePicker like here https://material-ui-pickers.dev/demo/datetime-picker would be amazing.

mckaragoz commented 2 years ago

As an alternative, we created MudDateWheelPicker as extension. It both have date and time selection.

NuGet: https://www.nuget.org/packages/CodeBeam.MudExtensions/6.0.9 Try online: https://mudextensions.azurewebsites.net/muddatewheelpicker

KieranFleckney commented 1 year ago

I would love this compontent too. For the momenmt I have made a work around version. I want to share it here for other too. By any means is it perfect or bug free. It also doesn't support all the feature of both current date and time pickers.

DateTime Picker `MudDateTimePicker.razor` ```cs @using MudBlazor.Extensions @using MudBlazor.Utilities @using System.Globalization @inherits MudPicker @Render @code { #region PickerContent protected override RenderFragment PickerContent => @
@if (!DisableToolbar) {
@GetFormattedYearString() @GetTitleDateString()
@if (AmPm) {
AM PM
}
@GetHourString():@GetMinuteString()
}
@if (_activeIndex == 0) { } else if (_activeIndex == 1) { }
; #endregion #region Parameters [Parameter] public DateTime? DateTimeValue { get => _value; set => SetDateTimeAsync(value, true).AndForget(); } [Parameter] public EventCallback DateTimeValueChanged { get; set; } /// /// The current month of the date picker (two-way bindable). This changes when the user browses through the calender. /// The month is represented as a DateTime which is always the first day of that month. You can also set this to define which month is initially shown. If not set, the current month is shown. /// [Parameter] public DateTime? PickerMonth { get; set; } /// /// Format of the selected date in the title. By default, this is "MMM dd" which abbreviates day and month names. /// For instance, display the long names like this "dddd, dd. MMMM". /// [Parameter] public string TitleDateFormat { get; set; } = "MMM dd"; /// /// Function to determine whether a date is disabled /// [Parameter] public Func IsDateDisabledFunc { get => _isDateDisabledFunc; set { _isDateDisabledFunc = value ?? (_ => false); } } private Func _isDateDisabledFunc = _ => false; /// /// If AutoClose is set to true and PickerActions are defined, selecting a day will close the MudDatePicker. /// [Parameter] public bool AutoClose { get; set; } /// /// Sets the amount of time in milliseconds to wait before closing the picker. This helps the user see that the date was selected before the popover disappears. /// [Parameter] public int ClosingDelay { get; set; } = 100; /// /// String Format for selected date view /// [Parameter] public string DateFormat { get { return (Converter as DefaultConverter)?.Format; } set { if (Converter is DefaultConverter defaultConverter) { defaultConverter.Format = value; _dateFormatTouched = true; } DateFormatChanged(value); } } private bool _dateFormatTouched; /// /// If true, set 12 hour selection clock /// [Parameter] public bool AmPm { get; set; } #endregion #region PrivateVariables private int _activeIndex = 0; private MudDatePicker _datePicker; private MudTimePicker _timePicker; private DateTime? _dateValue; private TimeSpan? _timeValue; private bool IsAm => _timeValue?.Hours >= 00 && _timeValue?.Hours < 12; private bool IsPm => _timeValue?.Hours >= 12 && _timeValue?.Hours < 24; private int _hourClicked = 0; #endregion private async Task SetDateTimeAsync(DateTime? date, bool updateValue) { if (_value != date) { Touched = true; if (date is not null && IsDateDisabledFunc(date.Value.Date)) { await SetTextAsync(null, false); return; } _value = date; _dateValue = date?.Date; _timeValue = date?.TimeOfDay; if (updateValue) { Converter.GetError = false; await SetTextAsync(Converter.Set(_value), false); StateHasChanged(); } await DateTimeValueChanged.InvokeAsync(_value); await BeginValidateAsync(); FieldChanged(_value); } } private void DateValueChanged(DateTime? date) { _dateValue = date; SelectTab(1); } private bool ampmCliked = false; private void TimeValueChanged(TimeSpan? time) { _timeValue = time; if (ampmCliked) { ampmCliked = false; return; } @if (_hourClicked == 1) SubmitAndClose(); _hourClicked += 1; } protected override async void Submit() { if (GetReadOnlyState()) return; if (_dateValue is null) return; if (_timeValue is null) _timeValue = new TimeSpan(); var newDate = new DateTime( _dateValue.Value.Year, _dateValue.Value.Month, _dateValue.Value.Day, _timeValue.Value.Hours, _timeValue.Value.Minutes, _timeValue.Value.Seconds, _timeValue.Value.Milliseconds ); await SetDateTimeAsync(newDate, true); } protected virtual async void SubmitAndClose() { if (PickerActions == null || AutoClose || PickerVariant == PickerVariant.Static) { Submit(); if (PickerVariant != PickerVariant.Static) { await Task.Delay(ClosingDelay); Close(false); } } } protected override void OnClosed() { SelectTab(0); base.OnClosed(); } private Task DateFormatChanged(string newFormat) { Touched = true; return SetTextAsync(Converter.Set(_value), false); } private string GetFormattedYearString() { return (PickerMonth ?? DateTime.Today.StartOfMonth(Culture)).ToString("yyyy", Culture); } private string FormatTitleDate(DateTime? date) { return date?.ToString(TitleDateFormat ?? "ddd, dd MMM", Culture) ?? ""; } private string GetTitleDateString() { return FormatTitleDate(_dateValue ?? DateTimeValue); } private string GetHourString() { if (_timeValue is null) return "--"; var h = _timeValue.Value.Hours; if (AmPm) { h = _timeValue.Value.Hours % 12; if (h == 0) h = 12; } return Math.Min(23, Math.Max(0, h)).ToString(CultureInfo.InvariantCulture); } private string GetMinuteString() { if (_timeValue is null) return "--"; return $"{Math.Min(59, Math.Max(0, _timeValue.Value.Minutes)):D2}"; } private void OnAmClicked() { if (_timeValue is null) return; var h = _timeValue.Value.Hours % 12; ampmCliked = true; _timeValue = new TimeSpan(0, h, _timeValue.Value.Minutes, _timeValue.Value.Seconds, _timeValue.Value.Milliseconds); FocusAsync().AndForget(); } private void OnPmClicked() { if (_timeValue is null) return; var h = _timeValue.Value.Hours; if (h <= 12) h += 12; h %= 24; ampmCliked = true; _timeValue = new TimeSpan(0, h, _timeValue.Value.Minutes, _timeValue.Value.Seconds, _timeValue.Value.Milliseconds); FocusAsync().AndForget(); } protected string AmButtonClass => new CssBuilder("mud-timepicker-button mud-button-year") .AddClass($"mud-timepicker-toolbar-text", !IsAm) // gray it out .Build(); protected string PmButtonClass => new CssBuilder("mud-timepicker-button mud-button-year") .AddClass($"mud-timepicker-toolbar-text", !IsPm) // gray it out .Build(); public override async void Clear(bool close = true) { await SetDateTimeAsync(null, true); StateHasChanged(); if (AutoClose) { Close(false); } } private void SelectTab(int index) { _activeIndex = index; _hourClicked = 0; } } ``` `MudDateTimePicker.razor.cs` ```cs using System.Globalization; using MudBlazor; namespace {your namespace}; public partial class MudDateTimePicker : MudPicker { public MudDateTimePicker() : base(new DefaultConverter { Format = "g", Culture = CultureInfo.CurrentCulture }) { AdornmentAriaLabel = "Open Date Time Picker"; } } ```
Example `Basic` ```cs ``` `With Action buttons` ```cs Clear Cancel Ok ``` ![unnamed](https://github.com/MudBlazor/MudBlazor/assets/57374898/245d0bc9-29c5-4c84-a37c-16da296e4077) ![unnamed (1)](https://github.com/MudBlazor/MudBlazor/assets/57374898/93e92f63-c7c3-4634-aac2-35044638a03c) ![unnamed (2)](https://github.com/MudBlazor/MudBlazor/assets/57374898/96a49183-3f8e-4b8c-ae6c-d8c07eb6c8ca) ![unnamed (3)](https://github.com/MudBlazor/MudBlazor/assets/57374898/64a845e6-138c-428e-a3ff-0de822e6e5df) ![unnamed (4)](https://github.com/MudBlazor/MudBlazor/assets/57374898/0f423765-5c42-4898-9990-20b4ec53753a)


I think there would be a lot of work need to be done to add full version. From my time looking at both the date and time picker currently. I see few options which the Core MudBlazor Team could go down:

henon commented 1 year ago

Option 2 would probably be a good compromise

kasgithub8 commented 3 months ago

Any news on this?

henon commented 3 months ago

Any news on this?

See draft PR by @ralvarezing: https://github.com/MudBlazor/MudBlazor/pull/7951

ralvarezing commented 3 months ago

Any news on this?

Been busy with other projects lately and not able to work on this, but I'll see to resume dev

jcaruso001 commented 1 month ago

That PR Looks so close!