Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to create an Editor Template for a DateTime field.
The display of the field works as it should, however when the field gets posted back top the server it looses its value. I'm using flatpickr for the date part and the time part.

My Class:
C#
public class myClass
{
    [Key]
    public int Id { get; set; }

    [UIHint("DateTime")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd HH:mm}")]
    [DataType(DataType.DateTime)]
    public DateTime MyDateTime { get; set; }
}


Controller
C#
public ActionResult Edit()
{
    var myClass = new myClass
    {
        Id = 1,
        MyDateTime = DateTime.Now,
    };
    ViewBag.Language = "en-US"; // "fr-FR"; //
    ViewBag.MinDate = new DateTime(2022, 4, 1, 0, 0, 0).Date.ToString("yyyy-MM-dd");
    ViewBag.MaxDate = DateTime.Today.Date.ToString("yyyy-MM-dd");
    return View("Edit2", myClass);
}


My View
HTML
@model EditorTemplates.Models.myClass

@{
    ViewBag.Title = "Edit2";
}

<h2>Edit2</h2>

@using (Html.BeginForm("Edit", "Home", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>myClass</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.MyDateTime, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.MyDateTime, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.MyDateTime, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>


My Editor Template (DateTime.cshtml)
HTML
<pre>@* usage : @Html.EditorFor(m => m.BirthDate, new { Language = 'fr-FR', MinDate = '2022-04-01', MaxDate = '2022-04-05' }) *@
@model System.DateTime
@{
    //var value = Model.ToString("yyyy-MM-dd [HH:mm]");
    var yearPart = Model.Year.ToString("0000");
    var monthPart = Model.Month.ToString("00");
    var dayPart = Model.Day.ToString("00");
    var datePart = $"{yearPart}-{monthPart}-{dayPart}";
    var hourPart = Model.Hour.ToString("00");
    var minutePart = Model.Minute.ToString("00");
    const string secondPart = "00";
    var timePart = $"{hourPart}:{minutePart}";
    Console.WriteLine($"{datePart} [{hourPart}:{minutePart}:{secondPart}]");
}
<div class="input-group" style="width: 320px">
    
    @Html.TextBox("date", datePart, new { @class = "form-control", @style = "min-width:220px", @id = "DatePart" })
    ^__i class="far fa-clock fa-1x" aria-hidden="true">
    @Html.TextBox("time", timePart, new { @class = "form-control", @style = "min-width:80px; max-width:80px", @id = "TimePart" })
</div>
@Html.TextBox("value", Model, new { @id = "Value", @class = "form-control", @readonly ="readonly" })
<script type="text/javascript">
    let locale = '@ViewBag.Language';
    let altFormat = 'F j, Y';
    if (locale === 'fr-FR') altFormat = 'j F Y';
    flatpickr('#DatePart',
        {
            altFormat: altFormat, // Exactly the same as date format, but for the altInput field
            altInput: true,       // Show the user a readable date (as per altFormat), but return something totally different to the server.
            allowInput: true,
            allowInvalidPreload: true, // Allows the preloading of an invalid date. When disabled, the field will be cleared if the provided date is invalid
            dateFormat: 'Y-m-d',
            enableTime: false,
            locale: '@ViewBag.Language',
            minDate: '@ViewBag.MinDate',
            maxDate: '@ViewBag.MaxDate',
            onChange: function (selectedDates, dateStr, instance) {
                console.log("onChange flatpickr date");
                set();
            }
        });
    flatpickr('#TimePart',
        {
            allowInput: true,
            enableTime: true,
            noCalendar: true,
            dateFormat: "H:i",
            time_24hr: true,
            onChange: function (selectedDates, dateStr, instance) {
                console.log("onChange flatpickr time");
                set();
            }
    });
    function set() {
        let dmy = document.getElementById('DatePart').value;
        console.log(`DatePart: ${dmy}`);
        // remove time part
        if (dmy.split(' ').length > 1) dmy = dmy.split(' ')[0];
        //console.log(dmy);

        let sep = '-';
        if (dmy.split(sep).length !== 3) sep = '/';
        const year = dmy.split(sep)[0];
        const month = dmy.split(sep)[1];
        const day = dmy.split(sep)[2];
        //console.log(`${year}/${month}/${day}`);

        //let hour = document.getElementById('HourPart').value;
        //if (hour.length === 1) hour = `0${hour}`;
        //let min = document.getElementById('MinutePart').value;
        //if (min.length === 1) min = `0${min}`;
        //console.log(`set: ${dmy} [${hour}:${min}]`);

        const hm = document.getElementById('TimePart').value;
        console.log(`TimePart: ${hm}`);
        sep = ':';
        const hour = hm.split(sep)[0];
        const min = hm.split(sep)[1];

        console.log(`Year    : ${parseInt(year)}`);
        console.log(`Month   : ${parseInt(month)}`);
        console.log(`Day     : ${parseInt(day)}`);
        console.log(`Hour    : ${parseInt(hour)}`);
        console.log(`Minute  : ${parseInt(min)}`);

        const dt = (`${year}-${month}-${day}`);
        console.log(`date : ${dt}`);
        const tm = (`${hour}:${min}`);
        console.log(`time : ${tm}`);
        const dtm = (`${month}/${day}/${year} ${hour}:${min}:00`);
        console.log(`dtm  : ${dtm}`);
        const date = new Date(parseInt(year), parseInt(month)-1, parseInt(day), parseInt(hour), min);
        console.log(`js date :${date}`);
        document.getElementById("DatePart").value = dt;
        //console.log(date.getHours() + ":" + date.getMinutes());
        document.getElementById("TimePart").value = tm;
        document.getElementById("Value").value = dtm;
    };
</script>



What I have tried:

I've tried several things, but each time the date gets posted to the controller as Jan 1st, 0001, [00:00].
Posted
Updated 14-Apr-22 5:53am

1 solution

The issue was that the model itself was not stored in the Editor Template:
once I replaced:
@Html.TextBox("value", Model, new { @id = "Value", @class = "form-control", @readonly ="readonly" })

by
@Html.HiddenFor(model => model, new { @id = @dateTimeId, @class = "form-control", @readonly = "readonly" })

I got the value back for the DateTime...
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900