5

I have a form where validation occurs in jQuery's validation plugin. My form contains two elements, an input type=file and a submit button. The user will select an image, and if that image is less than 500px, it won't be accepted and an error message should be shown. I have made a new method for this called width, but it's not working for some reason. The error message is not shown when I try to submit an image less than 500px. Here's my jsfiddle.

HTML

<form class="some_form" enctype="multipart/form-data" method="post" action="">
  <input type="file" name="photo" id="photoInput" />
  <input type="submit">
</form>

jQuery

$.validator.addMethod('width', function(value, element) {
  if ($(element).data('width')) {
    return $(element).data('width') >= 500;
  }

  return true;
}, 'Image needs to be wider than 500px');

$(".some_form").validate({
  rules: {
    photo: {
      required: true,
      width: 500
    }

  },

  messages: {
    photo: {
      required: "You must insert an image",
      width: "Your image's width must be greater than 500px"
    },
  }

});
31
  • Image width doesn't magically appear in element data by itself. You need to process the image file yourself first Commented Jul 16, 2016 at 4:31
  • @charlietfl How would I do that? Commented Jul 16, 2016 at 4:36
  • need to use FileReader API Commented Jul 16, 2016 at 4:37
  • @charlietfl How do I combine the usage of FileReader with the jQuery validation plugin though? Commented Jul 16, 2016 at 4:40
  • 1
    I added to your jsfiddle to get you a bit further along. It now loads the selected image into a new <img> element. You would now have to tie that into the JQuery Validator method. Commented Jul 16, 2016 at 5:03

1 Answer 1

9

You can load the image file into an <img> element, and then get the width of that element.


First add a container element to your HTML to hold the <img> element:

<form class="some_form" enctype="multipart/form-data" method="post" action="">
  <input type="file" name="photo" id="photoInput" />
  <input type="submit">
</form>
<div id="imgContainer"></div>

Next, define a custom Validator method:

$.validator.addMethod('minImageWidth', function(value, element, minWidth) {
  return ($(element).data('imageWidth') || 0) > minWidth;
}, function(minWidth, element) {
  var imageWidth = $(element).data('imageWidth');
  return (imageWidth)
      ? ("Your image's width must be greater than " + minWidth + "px")
      : "Selected file is not an image.";
});

Notes:

  1. As you can see, the method expects that it can get the image width by calling .data('imageWidth') on the file input element. We will be setting that value in code shown below.
  2. Also, the method assumes that when .data('imageWidth') returns undefined, the selected file is not an image.

You can now use the minImageWidth method like this:

var validator = $('.some_form').validate({
  rules: {
    photo: {
      required: true,
      minImageWidth: 500
    }
  },
  messages: {
    photo: {
      required: "You must insert an image"
    },
  }
});

Finally, add a change-event handler for the file input that creates the <img> element and adds it to the container. It will also set the .data('imageWidth') value on the file input element.

var $submitBtn = $('.some_form').find('input:submit'),
  $photoInput = $('#photoInput'),
  $imgContainer = $('#imgContainer');

$('#photoInput').change(function() {
  $photoInput.removeData('imageWidth');
  $imgContainer.hide().empty();

  var file = this.files[0];

  if (file.type.match(/image\/.*/)) {
    $submitBtn.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();
        var imageWidth = $img.width();
        $photoInput.data('imageWidth', imageWidth);
        if (imageWidth < 500) {
          $imgContainer.hide();
        } else {
          $img.css({ width: '400px', height: '200px' });
        }
        $submitBtn.attr('disabled', false);

        validator.element($photoInput);
      });
    }

    reader.readAsDataURL(file);
  } else {
    validator.element($photoInput);
  }
});

Notes:

  1. When the image is loaded, its width is placed as a .data('imageWidth') value on the file input element.
  2. While the image is loading, the submit button is disabled so the user cannot submit the form.
  3. The validation is performed immediately after the image is loaded. That is, the user does not have to click the submit button in order to for the error message to show up. This is accomplished by the call to validator.element().
  4. You cannot get the width of the <img> element until it is added to the DOM. It must also be visible, but the code above shows how it can be hidden right after if desired.

jsfiddle


References:

Sign up to request clarification or add additional context in comments.

5 Comments

Great answer! Thanks a lot!
@user2896120 - I made some improvements to my answer: (1) It now shows a different error message if the selected file is not an image, and (2) The validation is now performed immediately after the file is selected.
Looks great and works great as well! If I were to add height validation, would I need to add another addMethod()?
@user2896120 - You could go either way. You could add a minImageHeight method, or you could change the minImageWidth method into a minImageSize method, like this.
I have a form where it's dynamically cloned multiple times. Is there a way to make each form unique with its own image? To not confuse you, here's another question I have here with the code you provided to me, used in my work: (stackoverflow.com/questions/38416454/…)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.