2017-02-14 77 views
1

我有一个html表,我通过AJAX使用jQuery dataTables填充。我在页面上有两种形式,第一种形式验证可以正常工作的表格参数。验证事件侦听器上的动态表行

第二个验证包裹了整个表格,我的目标是使用工具提示创建自定义验证,除非有另一种方法可以使用提交表单验证方法来验证多个输入[type ='number']和日期选择器每一行:

input[type=number]事件 - 点击,KEYUP输入框的类型=数字

input[NAME=BUYDATE](.hasDatePicker)事件 - onfocusout在

我应该如何触发提交行的形式?

一个:在其中相同的元件使用的名称的时间验证一行= ELEMENT

B:使用所述提交表单验证方法验证整个形式?

此表是一个动态订单项实用

这里是我的dataTable与样本行:

<form id="ITEMS"> 
    <table id="table_001" class="xs-small table table-condensed" > 
    <thead> 
    <H5>Program: FRESH INCENTIVE</H5> 
    <H5>Customer: 330-990076-033 (B/C MANISTEE CLARK)</H5> 
    <p><font color="red">Delivery Days: Mon,Thu</font></p> 
    <tr> 
    <th></th> 
    <th class="hidden"> 
    [ 
{ "size" : "lg", 
    "upper_hidden" : [], 
    "lower_hidden" : [1,2,3,4,5,6,7,8,9,10,11,12] 
    }, 
    { "size" : "md", 
    "upper_hidden" : [], 
    "lower_hidden" : [1,2,3,4,5,6,7,8,9,10,11,12] 
    }, 
    { "size" : "sm", 
    "upper_hidden" : [3,4], 
    "lower_hidden" : [1,2,5,6,7,8,9,10,11,12] 
    }, 
    { "size" : "xs", 
    "upper_hidden" : [3,4,5], 
    "lower_hidden" : [1,2,6,7,8,9,10,11,12] 
    } 
    ] 
    </th> 
    <th>Item</th> 
    <th class='cupc'>UPC</th> 
    <th>Pack</th> 
    <th>Size</th> 
    <th>Description</th 
    <th>Mon<br>Qty</th> 
    <th>Tue<br>Qty</th> 
    <th>Wed<br>Qty</th> 
    <th>Thu<br>Qty</th> 
    <th>Fri<br>Qty</th> 
     <th>Sat<br>Qty</th> 
    <th>Start Date</th> 
    </tr> 
    </thead> 
    <tbody> 
    <tr role="row" class="odd"><td class="hidden-lg hidden-md"><span class="row-details row-details-close"><i class="fa fa-plus-square icon-large"></i></span></td><td class=" hidden">place holder</td><td><span class="EmptyRow itno live" title="ITEMNO:1525252" style="padding: 3px;">1525252</span></td><td><span class="UPC" title="UPC:010700807229">010700807229</span></td><td class="hidden-sm hidden-xs"><span class="pack" title="package qty:24">24</span></td><td class="hidden-sm hidden-xs"><span class="size" title="size:CT">CT</span></td><td class="hidden-xs"><span class="descrpt" title="desc:PAYDAY">PAYDAY</span></td><td><span title="Monday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between 1-99" value="" data-delday="1" data-dow="" class="qty non-day" maxlength="2"></span></td><td><span title="Tuesday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between 1-99" value="" maxlength="2" class="qty non-day" data-delday="2" data-dow=""></span></td><td><span title="Wednesday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between 1-99" value="" maxlength="2" class="qty non-day" data-delday="3" data-dow=""></span></td><td><span title="Thursday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between1-99" value="" maxlength="2" class="qty non-day" data-delday="4" data-dow=""></span></td><td><span title="Friday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between 1-99" value="" maxlength="2" class="qty delivery-day" data-delday="5" data-dow="5"></span></td><td><span title="Saturday:"><input type="number" min="1" max="99" name="QTY" title="Qty must be between1-99" value="" maxlength="2" class="qty non-day" data-delday="6" data-dow=""></span></td><td><span title="Start date for buying item"><input type="text" size="10" class="dp form-control-inline xs-small hasDatepicker" id="1" value="" name="BUYDATE" data-buydate=""><img class="ui-datepicker-trigger" src="/images/calendar.png" alt="Select a start buying date" title="Select a start buying date"></span></td></tr> 
    </tbody> 
    </table> 
    </form> 

是否可以使用,即使它违背了名字=值的方法典型的DOM准则,你有重复相同的唯一ID /名称?

我想,如果所有的行强调即使目标是在用户已集中在排红色不要紧

注:

每一行的最后一列有他们自己的日期选择器,如果该行中的任何其他列都有值,则必须提供该行的日期。

随后,如果提供了日期并且该行的其他输入字段(012xx)中没有任何一个具有提供的值,那么我需要触发一个错误。

基本上,

我有两种类型的类.RecordRow.EmptyRow识别行。

至少一个input[name='QTY']必须有一个值,如果该行是.EmptyRow,如果一个RecorRow你可能想要删除所有Qtys。

只有当用户触发两个事件侦听器之一时,每行的input[name='BUYDATE']都必须输入有效的日期。

有效期:

enter image description here

enter image description here

无效: enter image description here

enter image description here

这是我迄今为止

jQuery验证:

$("input").on("blur keyup", function(){ 
     row.children("td").each(function(){ 
      $(this).children('input').each(function() { 
      if($(this).attr("name") === 'BUYDATE') && $(this).valid()){ 
       //validate tds 
      } 
      }); 
     }); 
    }); 

form.validate({ 
     focusInvalid: false, 
     onkeyup: function(element) { rule!! 
      var element_id = $(element).attr('name'); 
      if (this.settings.rules[element_id]) { 
       if (this.settings.rules[element_id].onkeyup !== false) { 
        $.validator.defaults.onkeyup.apply(this, arguments); 
       } 
      } 
     }, 
     rules: { 
      "BUYDATE": { 
       required: { depends:function(){ 
          //iterate through rows here? 
          //this only validate onn submit 
          //I guess maybe on could trigger submit onkeyup 
          //or blur? 
         } 
       } 
      }, 
      "DLOCN": { 
       required:{ 
       depends: function(){ 
          //iterate through rows here? 
          //this only validate onn submit 
          //I guess maybe on could trigger submit onkeyup 
          //or blur? 
       } 
       } 
      } 
     }, 
     messages: { // custom messages 
      "EVENT": { 
       required: "Select a Program.", 
       HTH_SelectValue: "Select a Program."    
      }, 
      "LOCN": { 
       HTH_SingleLOCN: "A single location must be selected when using this option to load items." 
      }, 
      "DLOCN": { 
       required: "A customer location must be supplied when using this option to load items." 
      } 
     },   
     showErrors: function(errorMap, errorList) { 
      FormError.hide(); 
      // Clean up any tooltips for valid elements 
      $.each(this.validElements(), function (index, element) { 
       element = $(element); 
       NoError_ToolTip(element); 
      }); 
      // Create new tooltips for invalid elements 
      $.each(errorList, function (index, error) { 
       element = $(error.element); 
       message = error.message; 
       Error_ToolTip(element,message); 
       FormError.show(); 
      }); 
     },     
     invalidHandler: function (event, validator) { //display error alert on form submit  
      success.hide(); 
      FormError.show(); 
      $(document).scrollTop($(".form-body:first-of-type").offset().top); 
     }, 
     submitHandler: function (form) { 
      success.show(); 
      FormError.hide(); 
      // Submit1(form,FormError,success); 
     } 

    }); 
} 

最后,

有人会建议用表单包装每一行并验证那种方式吗?似乎如果我这样做,它会违反DOM准则,因为我需要使用Id来使用jQuery验证。我已经看到在单个页面上使用多个唯一ID,并且在某些情况下它可以工作。

回答

1

我决定使用两个事件侦听器来一次验证一个动态表行,其中我重置了两个事件侦听器上的验证;

A)上输入[类型=数]点击,关于日期选择器输入事件的内容KEYUP

&

B),和KEYUP

我使用内联复位验证规则即:

$(".element").rules('add',{required: true});

$(".element").rules('remove',"required");在飞行中。

我还在创建新行后动态创建新的$("#id").datepicker()对象。我也用$(this).clone()在处理原始行时创建动态行。我从来没有想过$.clone() API会有用,但我终于找到了一个有用的例子。

从我的理解克隆的对象不绑定到我认为依赖于API的原始行的事件侦听器。我实际上已经证明我用datepicker的嵌套输入文本克隆了一行。

我最终选择使用jQuery.remove()函数删除输入文本框,然后重新创建它并将其绑定到datepicker API,然后为其提供一个新ID以使其正确工作。

现在的问题是changeDate事件没有绑定到新的datepicker对象,我记得我试图删除id并添加一个新的id,但元素仍然绑定到从它克隆的原始元素的事件。

例如,日历在原始元素上弹出或日历本身不显示,具体取决于您如何选择重新初始化克隆行中的嵌套日期选择器。 (请参阅follow-up question I posted regarding the onchangeDate issue)。

也看出来哪个日期选择器API你引用因为有这个功能,如Bootstrap-datepickerjQuery-datepicker这矿是从美创,距离jQuery的日期选择器API许多API

我将展示样品如果有人遇到与我相同的问题,也可以使用这些代码。

注意:我没有在所有浏览器中测试2017年2月23日,所以我会在测试后更新。

这里是$.rules(), $.datepicker(), and $.clone() API的一些示例代码段:

这是我如何验证和处理表中的行,而无需使用$("form").submit()技术。

注:我的形式在我的桌子包裹所以我有一个验证的声明,但我不使用form.submit()技术,而我处理的,动态验证规则我重置和每个事件的触发设置。

function TableEventHandlers(){ 
    var form = $("#ITEMS"); 
    var FormError = $('.item-failure',form); 
    var FormSuccess = $('.item-success',form); 
    //used to trigger datepicker on calendar selection 
    $(".hasDatepicker").on("changeDate",function(e){ 
     e.stopImmediatePropagation(); 
     $(this).trigger("focusout"); 
     //alert("onchange date" + $(this).val() + e.type); 
    }); 

    //Processes a single qty at a time w/o popout 
    $("#table_001").on("click keyup",".qty",function (e) { 
     e.stopImmediatePropagation(); 
     //reset validators 
     $(".qty").rules('remove','min'); 
     $(".qty").rules('remove','max');  
     $(".qty").rules('remove','required'); 
     $(".dp").rules('remove','required'); 
     $(".dp").rules('remove','UsaDate'); 
     $(".dp").removeClass("error").tooltip("disable").tooltip("hide"); 
     $(".qty").removeClass("error").tooltip("disable").tooltip("hide"); 
     var row = $(this).closest('tr'); 
     flag = true; 
     row.find('.dp').rules('add',{required:true,messages:{required:"Must supply a start buy date."}}); 
     row.find('.dp').rules('add',{UsaDate:true,messages:{UsaDate:"Enter date in mm/dd/yyyy format"}}); 
     hasQtys = false; 
     hadOtherQtys = false; 
     var actualQty = parseInt($(this).val(), 10); 
     var dow = $(this).data("dow"); 
     var qty = $(); 
     var num = 0;    
     var buydate = row.find(".dp"); 
     var delday = ""; 
     var quans = 0; 
     var Error = false;  
     //iterate thru tr check if multiple records 
     row.children("td").each(function(index){ 
      qty = $(this).find(".qty"); 
      if(qty.val() !== undefined){ 
       num = parseInt(qty.val(), 10); 
       //console.log(isNaN(num)+ "index=" + index); 
       if(isNaN(num)) 
        num = 0; 
       if(num > 0){ 
        hasQtys = true; 
        if(quans > 1) 
         hadOtherQtys = true; 
        quans++; 
       } 
       //Min max validation process 
       console.log(num + ">"+ +parseInt(qty.attr("max"),10) + "<"+ parseInt(qty.attr("min"),10) + "not 0 = "+ num); 
       //qty out of range: min or Max attr or != 0? 
       if(num != 0 && (num > parseInt(qty.attr("max"),10) || num < parseInt(qty.attr("min"),10))) 
       { 
        if(num > parseInt(qty.attr("max"),10)){   
         qty.rules('add',{max: parseInt(qty.attr('max')), messages: {max: "Quantity must not be greater than " + qty.attr("max")}}); 
        } 
        else{ 
         qty.rules('add',{min: parseInt(qty.attr('min')), messages: {max: "Quantity must be greater than " + qty.attr("min")}}); 
        } 
         qty.addClass("error").tooltip("enable").tooltip('show'); 
         $('.item-failure').removeClass("hidden").show().html(qty.data("originalTitle")); 
         Error = true; 
       } 
       else 
        qty.removeClass("error").tooltip("disable").tooltip("hide"); 
      }//eof undefined qty 
     }); 
     console.log("has qtys= " + hasQtys + "has hadotherQtys = " + hadOtherQtys); 
     //.EmptyRow all require qtys when empty row 
     if(row.find(".itno").hasClass("EmptyRow") && hasQtys === false) 
     { 
      row.find(".qty").rules('add',{required: true, messages: {required: "Quantity must be entered when the item request date is new"}}); 
      row.find(".qty").addClass("error").tooltip("enable"); 
      Error = true; 
     } 
     else 
     { //.EmptyRow has Qtys or .RecordRow 
      row.find(".qty").rules('remove','required'); 
      //row.find(".qty").removeClass("error").tooltip("disable"); 
     } 
     console.log("buydate valid = " + buydate.valid() + "buydate.val = " + buydate.val()); 
     //new date is valid 
     if(buydate.valid() == false || buydate.val() == ""){ 
      $('.item-failure').removeClass("hidden").show().html("You have some errors. See below."); 
      row.find(".dp").addClass("error").tooltip("enable");  
      Error = true; 
     } 
     if(Error === true) 
      return true; 
     else{ 
      //Qtys met requirements of >= max && <= min or 0  
      buydate.removeClass("error").tooltip("disable"); 
      delday = qty.data("delday"); 
      $('.item-failure').addClass("hidden").hide(); 
      $('.item-success').removeClass("hidden").html("Processing future order request...").show(); 
      ProcessRequest(row,actualQty,delday, buydate.val()); 
     }//eof valid date 
    });//eof qty event listener 

    //Iterates thru the entire row when date changed 
    //NOTE: no popout atm causes erroneous results 
    $(".dp").on("keyup focusout",function (e) { 
     e.stopImmediatePropagation(); 
     //reset validators 
     $(".qty").rules('remove','min'); 
     $(".qty").rules('remove','max');  
     $(".qty").rules('remove','required'); 
     hasQtys = false; 
     hadOtherQtys = false; 
     var row = $(this).closest('tr'); 
     $(this).rules('add',{required:true,messages:{required:"Must supply a start buy date."}}); 
     $(this).rules('add',{UsaDate:true,messages:{UsaDate:"Enter date in mm/dd/yyyy format"}}); 
     var buydate = $(this); 
     var num = 0; 
     var dow = ''; 
     var delday = ''; 
     var quans = 0; 
      flag = true; 
     var qty = $(); 
     var Error = false; 
     //console.log("dp triggered" + e.type); 
     //only check date when manually entered. 
     if(e.type === "keyup" && ($(this).valid() === false || $(this).val() ==="")) 
     { console.log(e.type + $(this).valid()); 
      $(this).addClass("error").tooltip("enable").show(); 
      $('item-failure').removeClass("hidden").html("You have some errors. See below.").show(); 
      Error = true; 
     } 
     //check for qtys in row before processing  
     row.children("td").each(function(index){ 
      qty = $(this).find(".qty"); 
      if(qty.val() !== undefined){ 
       num = parseInt(qty.val(), 10); 
       if(isNaN(num)) 
        num = 0; 
       if(num > 0){ 
        hasQtys = true; 
        if(quans > 1) 
         hadOtherQtys = true; 
        quans++; 
       } 
       //Min max or 0 validation process 
       console.log(num + ">"+ +parseInt(qty.attr("max"),10) + "<"+ parseInt(qty.attr("min"),10) + "not 0 = "+ num); 
       console.log(num > parseInt(qty.attr('max'),10));; 
       //qty out of range: min or Max attr or != 0? 
       if(num != 0 && (num > parseInt(qty.attr("max"),10) || num < parseInt(qty.attr("min"),10))) 
       { 
        if(num > parseInt(qty.attr("max"),10)){   
         qty.rules('add',{max: parseInt(qty.attr('max')), messages: {max: "Quantity must not be greater than " + qty.attr("max")}}); 
        } 
        else{ 
         qty.rules('add',{min: parseInt(qty.attr('min')), messages: {max: "Quantity must be greater than " + qty.attr("min")}}); 
        } 
         qty.addClass("error").tooltip("enable").tooltip('show'); 
         $('.item-failure').removeClass("hidden").show().html(qty.data("originalTitle")); 
        Error = true; 
       } 
      }//eof undefined qty 
     }); 
      //Empty rows require atleast one qty 
      if(row.find(".itno").hasClass("EmptyRow") && hasQtys === false){ 
       row.find(".qty").rules('add',{required: true, messages: {required: "Quantity must be entered when the item request date is new"}}); 
       row.find(".qty").addClass("error").tooltip("enable"); 
       Error = true; 
      } 
      if(Error === true) 
       return true; 
      else{ 
      //Final stage of processing multiple records 
      row.children("td").each(function(){ 
      qty = $(this).find(".qty");  
      if(qty.val() !== undefined){ 
       num = parseInt(qty.val(), 10); 
       if(isNaN(num)) 
        num = 0; 
       //console.log("buydate.valid() = " +buydate.valid()); 
       //console.log(qty.val() + "<="+ qty.attr("max") +qty.val() + ">="+ qty.attr("min")); 
       if(buydate.valid() == "1" && buydate.val() !== "" && ((row.find(".itno").hasClass("EmptyRow") && hasQtys === true) || row.find(".itno").hasClass("RecordRow"))){ 
        $('.item-failure').addClass("hidden").hide(); 
        $('.item-success').removeClass("hidden").html("Processing future order requests...").show(); 
        console.log("processing.."); 
        ProcessRequest(row,num,delday); 
       } 

      }//eof qty.val undefined 
      });//eof td children 
     }//eof error 
    });//eof event datepicker listener 

    form.validate({ 
     focusInvalid: false, // do not focus the last invalid input 
     onkeyup: function(element) { //only allow if 'onkeyup:false' is rule!! 
      var element_id = $(element).attr('NAME'); 
      if (this.settings.rules[element_id]) { 
       if (this.settings.rules[element_id].onkeyup !== false) { 
        $.validator.defaults.onkeyup.apply(this, arguments); 
       } 
      } 
     }, 
     rules: { 
      //dynamic rules worked better in this instance 
     }, 
     messages: { 
      // same with custom messages 
     },   
     showErrors: function(errorMap, errorList) { 
      // Clean up any tooltips for valid elements 
      $.each(this.validElements(), function (index, element) { 
       element = $(element); 
       NoError_ToolTip(element); 
      }); 
      // Create new tooltips for invalid elements 
      $.each(errorList, function (index, error) { 
       element = $(error.element); 
       message = error.message; 
       Error_ToolTip(element,message); 
       FormError.html("You have some errors. Please check below.").show(); 
      }); 
     },     
     invalidHandler: function (event, validator) { //display error alert on form submit  
      FormError.html("You have some errors. Please check below.").show(); 
     }, 
     submitHandler: function (form) { 
      FormSuccess.html("Processing request...").show(); 
     } 

    }); 
    $.validator.addMethod("UsaDate", function(value, element) { 
      return this.optional(element) || /^\b\d{1,2}[\/]\d{1,2}[\/]\d{4}\b/.test(value); 
    }, "Please enter mm/dd/yyyy date format"); 
    } 

这里是我如何使用$ .clone()API从刚处理的行创建了一个新的空行:

var ProcessRequest = function(tr, count, dow){ 
     var success = $('#table_001_processing').css("color", "green").removeClass("hidden").show().html("Processing request..."); 
     //post vars 
     var recureItemNo = tr.find(".itno").html(); 
     var itemCount = count; 
     var dp = tr.find("[name='BUYDATE']"); 
     var newDate = dp.val(); 
     tempDate = dp.data("date"); 
     //clear all errors 
     tr.children("td").each(function(){ 
      $(".qty").each(function(){ 
       $(this).removeClass("error").tooltip("disable").tooltip("hide"); 
      }); 
     }); 
     //insert new row because we create new row off emptyRow 
     if(tr.find(".itno").hasClass("EmptyRow") && flag == true){ 
      console.log("this was an .EmptyRow"); 
      var randId = (Math.floor(Math.random() * 100 * 100)+1); 
      var $clone = tr.clone(); 
      $clone.insertBefore(tr); 
      //clear inputs 
      $clone.children("td").each(function(){ 
       var $input = $(this).find("input"); 
       $input.val(""); 
      }); 
      //destroy datepicker  
      var dp = $clone.find(".dp"); 
       dp.remove(); 
      //create new DatePicker(dp); 
      var dpId = $('#table_001 tr').length + 1; 
      $clone.find("td:eq(13) span").html("<input name='BUYDATE' class='dp form-control-inline' style='width:95px'; />"); 
      var newDp = $clone.find(".dp").attr("id",dpId); 
      DatePicker(newDp); 

     }else{//update took place which means future distribution no matter what 

     } 
     //getJSON web0572 complete stuff 
     //add-ons become future distributions by defaults 
     if(tr.find(".itno").hasClass("EmptyRow")) 
      tr.find(".itno").removeClass("EmptyRow").addClass("RecordRow").removeClass("live").addClass("future"); 
     if(tempDate > newDate) 
      tr.find(".itno").removeClass("live").addClass("future"); 
     if(tr.find(".itno").hasClass("future")) 
      tr.addClass("pending"); 
     //Call web057s2 add all of this below: 
     console.log("hasqtys ="+hasQtys+"itemno"); 
      //Display successful processing   
      if(hasQtys == true){  
      console.log("processed request add or update"); 
      if(hadOtherQtys == true && tr.find(".itno").hasClass("RecordRow")) 
       success.html("Item #" + recureItemNo + " successfully updated!");   
      else 
       success.html("Item #" + recureItemNo + " successfully added!"); 
      }else{ 
      console.log("processed request deleted row"); 
      tr.remove(); 
      success.html("Item #" + recureItemNo + " for " + tempDate + " successfully removed!"); 
      } 

      setTimeout(function(){ 
      success.addClass("hidden").hide().css("color","green").html("Processing..."); 
      }, 7000); 
      flag = false; 
} 

我发现,关键是创造动态的日期选择器是当你克隆一个对象覆盖旧的id,或者甚至是克隆对象的元素本身,这个例子可以在ProcessRequest函数里看到:

NOTE: I ha d与onChangeDate事件监听器一起玩一些游戏,以便处理datepicker关闭的行。现在唯一的问题是onChangeDate事件侦听器未在新克隆的对象上触发。我试图解除绑定事件并绑定它,但没有运气atm。

var DatePicker = function(that){ 
    if (jQuery().datepicker) { 
    //destroy old datepicker from clone 
    if(that.hasClass('hasDatepicker')){ 
     that.datepicker('remove'); 
    } 
     that.datepicker({ 
     showOn: "button", 
     buttonImage: "/images/calendar.png", 
     buttonImageOnly: true, 
     buttonText: 'Select a start buying date', 
     changeMonth: true, 
     changeYear: true, 
     beforeShow: function() { 
      setTimeout(function(){ 
       $('.ui-datepicker').css('z-index', 100100); 
      }, 0); 
     }, 
     onSelect: function() { 
     $(this).removeClass("error").tooltip("disable").tooltip("hide"); 
     $('.ui-datepicker').css('z-index', -1); 
     setTimeout(function(){ 
      //allows date to catchup 
     },0); 
    }, 
    onClose: function(){ 
     $(this).trigger("changeDate"); 
    }, 
     minDate: '+1', // The min date that can be selected, i.e. 30 days from the 'now' 
     maxDate: '+1y' // The max date that can be selected, i.e. + 1 month, 1 week, and 1 days from 'now' 
     //      HR MIN SEC MILLI 
     //new Date().getTime() + 24 * 60 * 60 * 1000) 
    }).datepicker(); 

    } 
} 

注:我一直在尝试使用类似的技术,我使用随机的ID与日期选择器用于创建dynamic bootstrap popout confirmation dialogs但我有一些错误的地方正在采取两次点击输入。如果我修复,我会发布结果。

我有一个datepicker错误,其中第一个选择不注册可能是因为它嵌套在一个事件内?在做了一些研究之后,我发现有一个similar issue with angular where user had to select date twice。我在OnClose中设置了一个setTimeout,它似乎可以解决问题。我将对弹出窗口使用相同的方法,看看它是如何发挥作用的。我希望我能帮助别人!


UPDATE: 感谢artemisian,我能够与动态datepickers解决的问题!关于克隆日期选择器请参阅this

var DatePicker = function(that){ 
    if (jQuery().datepicker) { 
    //alert(that.attr('id')); 
     that.datepicker({ 
     showOn: "button", 
     buttonImage: "/images/calendar.png", 
     buttonImageOnly: true, 
     buttonText: 'Select a start buying date', 
     changeMonth: true, 
     changeYear: true, 
     beforeShow: function() { 
      setTimeout(function(){ 
       $('.ui-datepicker').css('z-index', 100100); 
      }, 0); 
     }, 
     onSelect: function() { 
     $('.item-failure').addClass("hidden").hide(); 
     $(this).removeClass("error").tooltip("disable").tooltip("hide"); 
     $('.ui-datepicker').css('z-index', -1); 
     setTimeout(function(){ 
      //allows date to catchup 
     },0); 
    }, 
    onClose: function(){ 
     $(this).trigger("changeDate"); 
    }, 
     minDate: '+1', // The min date that can be selected, i.e. 30 days from the 'now' 
     maxDate: '+1y' // The max date that can be selected, i.e. + 1 month, 1 week, and 1 days from 'now' 
     //      HR MIN SEC MILLI 
     //new Date().getTime() + 24 * 60 * 60 * 1000) 
    }).datepicker(); 

    if($(this).hasClass("newDp")){ 
     $(this).bind("changeDate", function(e) { // this is the missing part in my opinion 
      e.stopImmediatePropagation(); 
      $(this).trigger("focusout"); 
      alert("onchange date" + $(this).val()); 
     }); 
    //Dynamic binding on cloned datepickers only 
    $(this).on("focusout",function(){ 
    RowValidation($(this)); 
    }); 
    } 
    } 
} 

那么我这样做,所以我不得不重用代码:

/************ ************************************************** * 包装功能允许动态绑定 **************************************** ****************************************/

var RowValidation = function(that){ 
     //reset validators 
     $(".qty").rules('remove','min'); 
     $(".qty").rules('remove','max');  
     $(".qty").rules('remove','required'); 
     hasQtys = false; 
     hadOtherQtys = false; 
     var row = that.closest('tr'); 
     that.rules('add',{required:true,messages:{required:"Must supply a start buy date."}}); 
     that.rules('add',{UsaDate:true,messages:{UsaDate:"Enter date in mm/dd/yyyy format"}}); 
     var buydate = that; 
     var num = 0; 
     var dow = ''; 
     var delday = ''; 
     var quans = 0; 
      flag = true; 
     var qty = $(); 
     var Error = false; 
     //console.log("dp triggered" + e.type); 
     //only check date when manually entered. 
     if(e.type === "keyup" && (that.valid() === false || that.val() ==="")) 
     { console.log(e.type + $(that.valid()); 
      that.addClass("error").tooltip("enable").show();  
      $('item-failure').removeClass("hidden").html("You have some errors. See below.").show(); 
      Error = true; 
     } 
     //check for qtys in row before processing  
     row.children("td").each(function(index){ 
      qty = $(this).find(".qty"); 
      if(qty.val() !== undefined){ 
       num = parseInt(qty.val(), 10); 
       if(isNaN(num)) 
        num = 0; 
       if(num > 0){ 
        hasQtys = true; 
        if(quans > 1) 
         hadOtherQtys = true; 
        quans++; 
       } 
       //Min max or 0 validation process 
       console.log(num + ">"+ +parseInt(qty.attr("max"),10) + "<"+ parseInt(qty.attr("min"),10) + "not 0 = "+ num); 
       console.log(num > parseInt(qty.attr('max'),10));; 
       //qty out of range: min or Max attr or != 0? 
       if(num != 0 && (num > parseInt(qty.attr("max"),10) || num < parseInt(qty.attr("min"),10))) 
       { 
        if(num > parseInt(qty.attr("max"),10)){   
         qty.rules('add',{max: parseInt(qty.attr('max')), messages: {max: "Quantity must not be greater than " + qty.attr("max")}}); 
        } 
        else{ 
         qty.rules('add',{min: parseInt(qty.attr('min')), messages: {max: "Quantity must be greater than " + qty.attr("min")}}); 
        } 
         qty.addClass("error").tooltip("enable").tooltip('show'); 
         $('.item-failure').removeClass("hidden").show().html(qty.data("originalTitle")); 
        Error = true; 
       } 
      }//eof undefined qty 
     }); 
      //Empty rows require atleast one qty 
      if(row.find(".itno").hasClass("EmptyRow") && hasQtys === false){ 
       row.find(".qty").rules('add',{required: true, messages: {required: "Quantity must be entered when the item request date is new"}}); 
       row.find(".qty").addClass("error").tooltip("enable"); 
       Error = true; 
      } 
      if(Error === true) 
       return true; 
      else{ 
      //Final stage of processing multiple records 
      row.children("td").each(function(){ 
      qty = $(this).find(".qty");  
      if(qty.val() !== undefined){ 
       num = parseInt(qty.val(), 10); 
       if(isNaN(num)) 
        num = 0; 
       //console.log("buydate.valid() = " +buydate.valid()); 
       //console.log(qty.val() + "<="+ qty.attr("max") +qty.val() + ">="+ qty.attr("min")); 
       if(buydate.valid() == "1" && buydate.val() !== "" && ((row.find(".itno").hasClass("EmptyRow") && hasQtys === true) || row.find(".itno").hasClass("RecordRow"))){ 
        $('.item-failure').addClass("hidden").hide(); 
        $('.item-success').removeClass("hidden").html("Processing future order requests...").show(); 
        console.log("processing.."); 
        ProcessRequest(row,num,delday); 
       } 

      }//eof qty.val undefined 
      });//eof td children 
     }//eof error 

}