动态克隆表单的jQuery图像验证



我的HTML中有一个表单,当用户点击#addOne按钮时,它将被克隆并动态附加。表单可以成功验证任何输入错误,我现在面临的唯一问题是它不能正确处理图像。假设我上传了第一张表格的图片,效果非常好。但当我点击#addOne按钮并上传第二个表单的图像时,问题就出现了。甚至在上传第二个表单的图像之前,它已经在页面上显示了上一个表单中的图像。上载此表单的图像将不会更新表单2。相反,它将更改表单1的显示图像。如何使每个表单显示自己上传的图像并进行正确验证?这是我的jsFiddle

HTML

<div class="article_properties">
  <form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
    <p style="display: inline">Page Number</p>
    <div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
      <p style="display: inline" class="pageNumber"></p>
    </div>
    <textarea style="display: none" class="inputNumber" name="pages"></textarea>
    <p>Image</p>
    <input style="padding: 0px" type="file" name="image" class="pageImg">
    <div class="imgContainer">
    </div>
    <p>Subtitle</p>
    <input type="text" name="subtitle">
    <p>Text</p>
    <textarea name="text" rows="4"></textarea>
    <input id="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
    <hr style="border: 1px dotted lightgray; margin-bottom: 50px">
  </form>

  <a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
  </a>
</div>
<!--End of article properties div-->
<div id="addOne">
  <p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
  <p>Finalize my article</p>
</div>

jQuery

var numPagesTemp = 4;
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
//Invoke functions for first form
add_validation_for_forms();
add_image_construction();
//Form validation
function add_validation_for_forms() {
  $(".article_properties_form").each(function() {
    $(this).validate({
      errorElement: 'div',
      rules: {
        image: {
          required: true,
          extension: "jpg|jpeg|png",
          minImageSize: {
            width: 600,
            height: 400
          }
        },
        subtitle: {
          required: true,
          minlength: 2,
          maxlength: 25
        },
        text: {
          required: true,
          minlength: 35,
          maxlength: 275
        }
      },
      messages: {
        image: {
          required: "This page needs an image",
          extension: "You're only allowed to upload jpg or png images."
        },
        subtitle: {
          required: "You have to provide a subtitle for this page!",
          minlength: "Your subtitle must be at least 2 characters long",
          maxlength: "Your subtitle must be less than 25 characters long"
        },
        text: {
          required: "Please enter text for this page",
          minlength: "Your text must be at least 35 characters long",
          maxlength: "Your text must be less than 275 characters long"
        },
      },
    });
  });
}
//Adding a form
$('#addOne').click(function() {
  numPagesTemp--;
  var articlePropsTemplate = $('.article_properties_form:last').clone();
  articlePropsTemplate.show();
  $('.article_properties').append(articlePropsTemplate);
  var articlePropsExpand = $('.expand:last').clone();
  articlePropsExpand.text("Expand " + numPagesTemp);
  articlePropsExpand.hide();
  $('.article_properties').append(articlePropsExpand);
  $('.pageNumber:last').text(numPagesTemp);
  $('.inputNumber:last').text(numPagesTemp);
  articlePropsTemplate[0].reset();
  add_validation_for_forms();
  add_image_construction();
  articlePropsTemplate.validate().resetForm();
  if (numPagesTemp == 1) {
    $('#addOne').hide();
    $(".nextBtn").show();
  }
});
//Adding Method
$.validator.addMethod('minImageSize', function(value, element, minSize) {
  var imageSize = $(element).data('imageSize');
  return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
}, function(minSize, element) {
  return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
});
//Image Uploading
var $properties_btn = $('properties_btn'),
  $imgContainer = $('.imgContainer'),
  $pageImg = $('.pageImg');
function add_image_construction() {
  $('.pageImg').change(function() {
    $pageImg.removeData('imageSize');
    $imgContainer.hide().empty();
    var file = this.files[0];
    if (file.type.match(/image/.*/)) {
      $properties_btn.attr('disabled', true);
      var reader = new FileReader();
      reader.onload = function() {
        var $img = $('<img />').attr({
          src: reader.result
        });
        $img.on('load', function() {
          $imgContainer.append($img).show();
          $pageImg.data('imageSize', {
            width: $img.width(),
            height: $img.height()
          });
          $img.css({
            width: '400px',
            height: '200px'
          });
          $properties_btn.attr('disabled', false);
          validator.element($pageImg);
        });
      }
      reader.readAsDataURL(file);
    } else {
      validator.element($pageImg);
    }
  });
}

克隆时我的建议是:

永远不要克隆已插入指令的元素。

所谓插入指令,我的意思是它们已经设置了JavaScript行为,比如事件处理。

相反,请执行以下操作:

(1) 在检测元素之前对其进行克隆,并将克隆保存在变量中。

var $CLONED_FORM = $('.article_properties_form:first').clone();

(2) 提供一个函数,该函数将对要克隆的元素集进行检测。

function initializeForm($form, pageNum) {
  // Set up form validation here.
  // Also attach the change-event handler for the file input here.
}

(3) 为页面上已经存在的集合调用函数。

$('.article_properties_form').each(function() {
  initializeForm($(this), numPagesTemp--);
});

(4) 当您想添加另一组元素时,克隆并添加它,然后调用它上的函数。

$('#addOne').click(function() {
  var $newForm = $CLONED_FORM.clone().appendTo('.article_properties').show();
  initializeForm($newForm, numPagesTemp--);
  if (numPagesTemp == 0) {
    $('#addOne').hide();
    $(".nextBtn").show();
  }
});

jsfiddle


您还需要将验证器对象存储在一个名为validator的变量中。

var validator = $form.validate({

此外,克隆时应避免id值重复。表单提交按钮上有一个id,但似乎不需要它,所以也许可以删除它。

我需要使用我的代码

编辑、更新

class="properties_btn"代替id="properties_btn"以防止重复的id被附加到document;在CCD_ 9事件中定义了CCD_。

$(function() {
  var numPagesTemp = 4;
  $('.pageNumber:last').text(numPagesTemp);
  $('.inputNumber:last').text(numPagesTemp);
  //Invoke functions for first form
  add_validation_for_forms();
  add_image_construction();
  //Form validation
  function add_validation_for_forms() {
      $(".article_properties_form").each(function() {
        $(this).validate({
          errorElement: 'div',
          rules: {
            image: {
              required: true,
              extension: "jpg|jpeg|png",
              minImageSize: {
                width: 600,
                height: 400
              }
            },
            subtitle: {
              required: true,
              minlength: 2,
              maxlength: 25
            },
            text: {
              required: true,
              minlength: 35,
              maxlength: 275
            }
          },
          messages: {
            image: {
              required: "This page needs an image",
              extension: "You're only allowed to upload jpg or png images."
            },
            subtitle: {
              required: "You have to provide a subtitle for this page!",
              minlength: "Your subtitle must be at least 2 characters long",
              maxlength: "Your subtitle must be less than 25 characters long"
            },
            text: {
              required: "Please enter text for this page",
              minlength: "Your text must be at least 35 characters long",
              maxlength: "Your text must be less than 275 characters long"
            },
          },
        });
      });
    }
    //Adding a form
  $('#addOne').click(function() {
    numPagesTemp--;
    var articlePropsTemplate = $('.article_properties_form:last')
      .clone();
    articlePropsTemplate.find("img").remove();
    $('.article_properties').append(articlePropsTemplate);
    var articlePropsExpand = $('.expand:last').clone();
    articlePropsExpand.text("Expand " + numPagesTemp);
    articlePropsExpand.hide();
    $('.article_properties').append(articlePropsExpand);
    $('.pageNumber:last').text(numPagesTemp);
    $('.inputNumber:last').text(numPagesTemp);
    $("form:last")[0].reset();
    add_validation_for_forms();
    // add_image_construction();
    articlePropsTemplate.validate().resetForm();
    if (numPagesTemp == 1) {
      $('#addOne').hide();
      $(".nextBtn").show();
    }
    
  });
  //Adding Method
  $.validator.addMethod('minImageSize', function(value, element, minSize) {
    var imageSize = $(element).data('imageSize');
    return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
  }, function(minSize, element) {
    return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
  });
  //Image Uploading
  //  var $properties_btn = $('.properties_btn'),
  //  $imgContainer = $('.imgContainer'),
  //  $pageImg = $('.pageImg');
  function add_image_construction() {
    $(document).on("change", ".pageImg", function(e) {
      var form = $(this).closest("form");
      var validator = form.validate();
      $(this).removeData('imageSize');
      form.find('.imgContainer').hide().empty();
      var file = this.files[0];
      if (file.type.match(/image/.*/)) {
        form.find('.properties_btn').attr('disabled', true);
        var reader = new FileReader();
        reader.onload = function() {
          var $img = $('<img />').attr({
            src: reader.result
          });
          $img.on('load', function() {
            form.find('.imgContainer').append($img).show();
            $(e.target).data('imageSize', {
              width: $img.width(),
              height: $img.height()
            });
            $img.css({
              width: '400px',
              height: '200px'
            });
            form.find('.properties_btn').attr('disabled', false);
            validator.element(e.target);
          });
        }
        
        reader.readAsDataURL(file);
      } else {
        validator.element(e.target);
      }
      
    });
  }
  
})
form {
  border: 1px solid blue;
  padding: 10px;
  margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/additional-methods.min.js"></script>
<div class="article_properties">
  <form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
    <p style="display: inline">Page Number</p>
    <div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
      <p style="display: inline" class="pageNumber"></p>
    </div>
    <textarea style="display: none" class="inputNumber" name="pages"></textarea>
    <p>Image</p>
    <input style="padding: 0px" type="file" name="image" class="pageImg">
    <div class="imgContainer">
    </div>
    <p>Subtitle</p>
    <input type="text" name="subtitle">
    <p>Text</p>
    <textarea name="text" rows="4"></textarea>
    <input class="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
    <hr style="border: 1px dotted lightgray; margin-bottom: 50px">
  </form>
  <a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
  </a>
</div>
<!--End of article properties div-->
<div id="addOne">
  <p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
  <p>Finalize my article</p>
</div>


这是您试图实现的简化版本,无需验证上传的文件

// maximum number of `form` elements which `document` should contain
var n = 4;
// display `form` index
function handleLabel() {
  $("label").html(function(index, html) {
    return "form #" + index 
  })
}
handleLabel();
function processFile() {
  // preview uploaded image
  $("<img>", {src: URL.createObjectURL(this.files[0])})
  .insertAfter(this.nextElementSibling).after("<br>");
  
}
// handle file upload; delegate event to `document`
$(document).on("change", ":file", processFile);
// append cloned `form` to page
$("button").on("click", function() {
  // if less than `n` forms
  if ($("form").length < 4) {
  // copy last `form` `.outerHTML` instead of using `.clone()`
  $($("form:last")[0].outerHTML)
    // remove `img` from `html`
    .find("img").remove().end()
    .insertAfter("form:last");
    // update `form` `label` elements
    handleLabel();
  } else {
    // detach `click` event from `button`
    // when four `form` elements exist in `document`
    $(this).off("click")
  }
});
// handle `form` submit event
$(document).on("submit", "form", function(e) {
  var img = $(this).find("img")[0];
  // check `img` `width`, `height`
  if (img.naturalWidth < 600 
    || img.naturalHeight < 400) {
      e.preventDefault();
      this.reset();
      alert("invalid img width or height")
    }
})
form {
  border: 1px solid blue;
  padding: 10px;
  margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<form>
  <fieldset>
    <label></label><br>
    <input name="file" type="file" accept=".jpg,.jpeg,.png" required />
    <br>
    <input type="submit" />
  </fieldset>
</form>
<button>
  add form
</button>

jsfiddlehttps://jsfiddle.net/hLjvffpv/5/

相关内容

  • 没有找到相关文章

最新更新