SventoryMang
SventoryMang

Reputation: 10478

Validate image upload unobtrusively using Jquery validate for dynamic forms?

I've got an image upload that is created on a dynamic form. I am trying to make it so that I can validate that the file uploaded is an actual image, and do this unobtrusively. I've read about the .rules() settings and using the accept property, but that requires you to input a field name (http://docs.jquery.com/Plugins/Validation/Methods/accept). Since the forms are dynamic I won't know the field name. My view that generates the upload input looks like this:

 <input type="file" size="20" name="@(Model.FormItem.Id + "-image")" id="@(Model.FormItem.Id + "-image")" />

So all my file inputs have an "-image" suffix. Is there a way to add a rule using a jquery selector for the validator rules instead of using a specific field name??

EDIT Alright it's clear that I am not explaining what the problem is well. Perhaps the solution is so simple and somehow I just missed it. I know how to use jQuery selectors, but from the examples I have seen of the rules syntax you have to supply a static field name for the rules. How can I assign validate rules to a selector instead of a static field name??

So right now this is what I have :

 var validatorData = $('#items-form').data('validator');

        $.extend(validatorData.settings, {
            rules: {
                static_field_name: { accept: "jpg|png" }
            },
            messages: {
                static_field_name_message: "The file must be an image."
            }
        });

Which won't work, nor does (obviously) if I replace static_field_name with the proper selector $('input[name$="-image"]'). So how do I do this?

Upvotes: 0

Views: 3667

Answers (3)

Tom Regan
Tom Regan

Reputation: 3841

Of course your answer works, I'm adding this as a slightly different way to skin the same cat.

In the c# code section of the cshtml page:

//only allow these file types for upload
var allowedUploadExtensions = ".CSV|.DOC|.DOCX|.JPG|.JPEG|.PDF|.XLS|.XLSX|.TIF|.TIFF";    
var acceptMessage = allowedUploadExtensions.Replace("|", ",");

In your $(document)ready function:

            $.validator.addMethod('isValidFileExtension', function (value, element) {
            if (value == '')
                return true;  //data-val-required will catch lack of value.
            var extension = value.substr((value.lastIndexOf('.'))).toUpperCase();
            var validFileExtensions = new String('@allowedUploadExtensions').toUpperCase().split('|');
            return $.inArray(extension, validFileExtensions) > -1;
        });

        $('.file-upload').rules('add', { isValidFileExtension: true, messages: { isValidFileExtension: 'Invalid file extension, valid extensions are @acceptMessage'} });

and then in your markup:

<input type="file" name="UploadedFile" id="UploadedFile" 
                    class="file-upload"
                    data-val="true" 
                    data-val-required="Please select a document to upload."/>

Upvotes: 0

SventoryMang
SventoryMang

Reputation: 10478

I found out how to do this using .addClassRules() like so:

$.validator.addClassRules("image-upload", {
       accept: "jpg|png|gif"
});

Then just apply class image-upload to the input. However, to also make it work unobtrusively I had to refactor the rules to get a custom message (http://docs.jquery.com/Plugins/Validation/Reference#Refactoring_rules):

$.validator.addMethod("acceptImageTypes", $.validator.methods.accept,
  "Selected File must be an image.");

        $.validator.addClassRules("image-upload", {
            acceptImageTypes: "jpg|png|gif"
        });

Then change my markup to:

<label>Image</label>
<input type="file" size="20" data-val="true" class="image-upload" name="@(Model.FormItem.Id + "-image")" id="@(Model.FormItem.Id + "-image")" />
<span class="field-validation-valid" data-valmsg-for="@(Model.FormItem.Id + "-image")" data-valmsg-replace="true">File must be an image.</span>

Upvotes: 1

Hososugi
Hososugi

Reputation: 380

I see 2 possible ways to solve this:

1) Using jQuery's .children() or $("#parent input:first") or $("input[type=file]:last") selectors so that your input doesn't require a static name.

2) Use a regex expression for your jQuery selector if you have any sort of pattern in the dynamic names given:
a) jquery way: http://api.jquery.com/attribute-ends-with-selector/
b) Or full regex way: http://james.padolsey.com/javascript/regex-selector-for-jquery/

That should be the hard part. Then you can add your rules like you would normally.

Upvotes: 0

Related Questions