2017-08-07 207 views
0

我试图使用弹出窗口模式在日历中创建事件,并且无法让jQuery验证工作事件的开始时间和结束时间字段。
我无法弄清楚如何验证这两个字段相互之间的关系,以便结束时间在开始时间之前无效。使用日期时间选择器(ASP.Net MVC Core v1.1)进行日期和时间验证

它似乎在第一次弹出窗体时显示的默认日期部分工作,但如果我更改开始日期,它将停止工作。另一方面,试图验证日期的时间部分从未奏效。

视图模型:

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; } 
} 

控制器:

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); 
    } 

索引视图:

<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>

任何suggesti ons将不胜感激!

编辑(20/08/2017) -
我试着结合使用微软的导游自定义的验证,但似乎并没有工作,要么(一个数据属性添加到浏览模式以及)。

校验类:

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

因此测试不同的选项,打破我的头在这几个星期后,我意识到,我一直在努力执行验证,原因有几个错误的逻辑:因为我是怎么建的

  1. 自定义的jQuery验证,被比较的开始日期的值只在页面加载时才传递给验证。因此,当用户改变开始字段的输入时它没有改变(所以它保持在默认值或空值)。
  2. 我完全忽略了日期对象存储时间的表情 - 正如我试图手动进行时间比较。

只花了修修补补的几分钟后,通过解决这些问题:

  1. 而不是传递参数的自定义验证,直接使用jQuery形式喂养它的开始日期。
  2. 摆脱所有手动小时比较代码并进行简单的日期比较。

现在的自定义验证码削减到3行简单:

 $.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"); 

感谢您的建议!

0

的最佳选择你的情况下,我认为是 'MVC万无一失验证'。您可以为您的案例使用“GreaterThan”或“LessThan”数据注释。所以,你可以在你的“终结”属性这样的事情在你annotaion:

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

检查this有关万无一失的更多信息。

+0

非常感谢你的建议!我一定会尝试一下。有什么类似的东西可以在飞行中进行客户端验证吗?由于它是一个弹出窗口模式,如果在用户将数据输入字段而不是在提交后弹出验证错误,则可能会更好。 –

+0

这将处理客户端的验证。 – Hadee

+0

我试过安装Foolproof Validation只是为了发现它不适用于MVC Core版本1.1。 是否有更新的类似插件,您知道吗?所有我能找到的与MVC Core完全不兼容。我也尝试使用自定义验证属性来比较这两个属性,但似乎也没有工作。 **我很抱歉花了这么长时间回复** - 我没有足够的时间坐下来在这个计划上工作一段时间。 –