Saya mencoba menggunakan modal sembulan untuk membuat acara di kalender, dan saya mengalami kesulitan mendapatkan validasi jQuery untuk bekerja pada bidang waktu mulai dan waktu berakhir untuk acara tersebut.
Saya tidak tahu bagaimana memvalidasi kedua bidang satu sama lain sehingga waktu berakhir tidak akan valid jika sebelum waktu mulai.

Tampaknya berfungsi sebagian pada tanggal default yang ditampilkan saat pertama kali formulir muncul, tetapi jika saya mengubah tanggal mulai itu berhenti berfungsi. Di sisi lain, mencoba memvalidasi bagian waktu dari tanggal tidak pernah berhasil.

Lihat model:

public class EventViewModel
{
    public int Id { get; set; }

    public string Title { get; set; }

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

    [Required]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd HH:mm}")]
    [DateGreaterThan("Start", ErrorMessage = "End date has to be later than start date")]
    public DateTime End { get; set; }

    public string Color { get; set; }

    public bool AllDay { get; set; }

    [Required]
    public string StudentId { get; set; }

    [Required]
    public int LessonTypeId { get; set; }
}  

Pengontrol:

public async Task<IActionResult> Index()
    {
        EventViewModel Event = new EventViewModel { Start = DateTime.Now, End = DateTime.Now.AddMinutes(30) };
        var user = await GetCurrentUserAsync();
        var studentList = await GetTeacherStudentsAsync(user);
        ViewData["StudentList"] = new SelectList(studentList, "Id", "FirstName");
        var lessonTypeList = _context.LessonTypes.Where(l => l.TeacherId.Equals(user.Id));
        ViewData["LessonTypeList"] = new SelectList(lessonTypeList, "LessonTypeId", "Description");
        return View(Event);
    }

Tampilan Indeks:

<head>
<script
  src="https://code.jquery.com/jquery-3.2.1.min.js"
  integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
  crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/css/tether.min.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.css" />
  <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/gcal.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/jquery.datetimepicker.css" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.full.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
  <script type="text/javascript">
    $(document).ready(function() {

      $('#calendar').fullCalendar({
        customButtons: {
          createButton: {
            text: "new event",
            click: function() {
              $('#createModal').modal('show');
            }
          }
        },
        header: {
          left: 'prev,next today createButton',
          center: 'title',
          right: 'month,agendaWeek,agendaDay,listWeek'
        },
        defaultView: "month",
        allDaySlot: false,
        eventLimit: true,
        editable: true,
        navLinks: true,
        events: "/Calendar/GetEvents",
        eventDrop: function(event, delta, revertFunc) {

          alert(event.title + " was dropped on " + event.start.format());

          if (confirm("Are you sure you want to make this change?")) {
            SaveEvent(event);
          } else {
            revertFunc();
          }

        },
        eventResize: function(event, delta, revertFunc) {

          alert(event.title + " is now from " + event.start.format() + " to " + event.end.format());

          if (confirm("Are you sure you want to make this change?")) {
            SaveEvent(event);
          } else {
            revertFunc();
          }

        }
      });

      $.validator.addMethod("laterThan", function(value, element, params) {
        var start = params.split(" ");
        var startDate = new Date(start[0]);
        var startTime = start[1].split(":");
        var end = value.split(" ");
        var endDate = new Date(end[0]);
        var endTime = end[1].split(":");
        if (startDate == endDate) {
          if (parseInt(startTime[0], 10) == parseInt(endTime[0], 10)) {
            return parseInt(startTime[1], 10) > parseInt(endTime[1], 10);
          } else if (parseInt(startTime[0], 10) < parseInt(endTime[0], 10)) return true;
          else return false;
        }
        return this.optional(element) || startDate < endDate;
      }, "End time must be later than start time");

      var validator = $("#createForm").validate({
        rules: {
          Start: "required",
          End: {
            required: true,
            laterThan: $("#Start").val(),
          }
        }
      });

      $(function() {
        $("#Start").datetimepicker({
          format: "Y-m-d H:i",
          onChangeDateTime: function(ct) {
            $(this).valid();
          }
        });
        $("#End").datetimepicker({
          format: "Y-m-d H:i",
          onShow: function(ct) {
            var start = $("#Start").val().split(" ");
            this.setOptions({
              minDate: start[0]
            });
          },
          onChangeDateTime: function(ct) {
            $(this).valid();
          }
        });
      });
    });


    function SaveEvent(Event) {

      var dataRow = {
        Id: Event.id,
        Start: Event.start,
        End: Event.end
      }

      $.ajax({
        method: 'POST',
        url: '@Url.Action("SaveEvent", "Calendar")',
        dataType: "json",
        contentType: "application/json",
        data: JSON.stringify(dataRow),
        error: function(result) {
          alert("Something went wrong... Event Id was: " + Event.id + ", Start Time was: " + Event.start.format());
        }
      });
    }

    function CreateEvent() {

      var valid = validator.form();
    }

    function DeleteEvent(Event) {

      var dataRow = {
        Id: Event.id
      }

      $.ajax({
        method: 'POST',
        url: '@Url.Action("DeleteEvent", "Calendar")',
        dataType: "json",
        contentType: "application/json",
        data: JSON.stringify(dataRow),
        error: function(result) {
          alert("Something went wrong... Event Id was: " + Event.id)
        }
      })

    }
  </script>
</head>

<body>
  <div id='calendar'></div>

  <div class="modal fade" id="createModal" tabindex="-1" role="dialog" aria-labelledby="createModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title" id="createModalLabel">Create New Event</h4>
          <button type="button" class="close" data-dismiss="modal">×</button>
        </div>
        <div class="modal-body">
          <form id="createForm">
            <div class="form-group">
              <label for="StudentId" class="col-md-2 form-control-label">Student</label>
              <div class="col-md-10">
                <select asp-for="StudentId" asp-items="ViewBag.StudentList" class="form-control"></select>
              </div>
            </div>
            <div class="form-group">
              <label for="LessonTypeId" class="col-md-3 form-control-label">Lesson Type</label>
              <div class="col-md-9">
                <select asp-for="LessonTypeId" asp-items="ViewBag.LessonTypeList" class="form-control"></select>
              </div>
            </div>
            <div class="form-group">
              <label for="Start" class="col-md-2 form-control-label">Start</label>
              <div class="col-md-10">
                <input asp-for="Start" class="form-control" id="Start" name="Start" />
              </div>
            </div>
            <div class="form-group">
              <label for="End" class="col-md-2 form-control-label">End</label>
              <div class="col-md-10">
                <input asp-for="End" class="form-control" id="End" name="End" />
              </div>
            </div>
          </form>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-primary" id="createButton" onclick="CreateEvent()">Create</button>
          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        </div>
      </div>
    </div>
  </div>
</body>

Setiap saran akan sangat dihargai!

Sunting (20/08/2017) -
Saya mencoba memasukkan validasi khusus menggunakan panduan Microsoft, tetapi itu sepertinya tidak berhasil (satu atribut data ditambahkan ke model tampilan juga).

Kelas Validasi:

public class DateGreaterThan : ValidationAttribute, IClientModelValidator
{
    private readonly string _earlierDate;

    public DateGreaterThan (string earlierDate)
    {
        _earlierDate = earlierDate;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ErrorMessage = ErrorMessageString;

        var lateDate = (DateTime)value;
        var otherProperty = validationContext.ObjectType.GetProperty(_earlierDate);
        if (otherProperty == null)
            throw new ArgumentException("Property with this name could not be found");

        var earlyDate = (DateTime)otherProperty.GetValue(validationContext.ObjectInstance);

        if (lateDate <= earlyDate)
            return new ValidationResult(ErrorMessage);

        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        var error = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
        context.Attributes.Add("data-val", "true");
        context.Attributes.Add("data-val-error", error);
    }
}
0
Denis Targansky 8 Agustus 2017, 01:59

2 jawaban

Jawaban Terbaik

Jadi setelah beberapa minggu menguji opsi yang berbeda dan mematahkan kepala saya karena ini, saya menyadari bahwa validasi yang saya coba terapkan memiliki logika yang salah karena beberapa alasan:

  1. Karena cara saya membuat validasi jQuery khusus, nilai tanggal mulai yang dibandingkan hanya diteruskan ke validasi satu kali - saat halaman dimuat. Oleh karena itu, itu tidak berubah ketika pengguna mengubah input untuk bidang awal (sehingga tetap pada default atau nol).
  2. Saya benar-benar mengabaikan wajah bahwa objek tanggal juga menyimpan waktu - karena saya mencoba melakukan perbandingan waktu secara manual.

Hanya perlu beberapa menit mengutak-atik setelah itu untuk memperbaiki masalah tersebut dengan:

  1. Alih-alih meneruskan parameter ke validasi khusus, berikan tanggal mulai langsung dari formulir menggunakan jQuery.
  2. Singkirkan semua kode perbandingan jam manual dan lakukan perbandingan tanggal sederhana.

Sekarang kode validasi khusus dipotong menjadi 3 baris sederhana:

        $.validator.addMethod("laterThan", function (value, element) {
            var startDate = new Date($("#Start").val());
            var endDate = new Date(value);

            return this.optional(element) || startDate < endDate;
        }, "End time must be later than start time");  

Terima kasih atas sarannya!

1
Denis Targansky 30 Agustus 2017, 03:10

Pilihan terbaik untuk kasus Anda, menurut saya adalah 'Validasi Mop MVC'. Anda dapat menggunakan anotasi data 'Lebih Besar' atau 'Kurang' untuk kasus Anda. Jadi Anda dapat memiliki sesuatu seperti ini di anotaion Anda di properti 'End' Anda:

[GreaterThan("Start", ErrorMessage = "Expiry Date must be greater than Activation Date", PassOnNull = true)]

Lihat ini untuk informasi selengkapnya tentang Foolproof.

0
Hadee 8 Agustus 2017, 00:18