Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Model Validation on a dynamic form?

I have the following Model :

public class FileModel
{
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(100, ErrorMessage = "Max is 100, Min is 3", MinimumLength = 3)]
    public string Name { get; set; }

    public string Path { get; set; }

    [Required(ErrorMessage = "Required")]
    public string FileTypeId { get; set; }

    public DateTime RegistrationDate { get; set; }
}

the following is my view :

@using (Html.BeginForm("Index", "FileManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <table class="content-table" style="min-width: 600px; border-spacing: 15px;">
        <tr>
            <td colspan="4" class="table-header">New File
                <div class="add-icon">+</div>
            </td>
        </tr>
        <tr>
            <td>Name: </td>
            <td>@Html.TextBoxFor(q => q.NewFile.Name, new { maxlength = "100", id = "NewFile_Name1", name = "NewFile.Name1" })
                <br />@Html.ValidationMessageFor(q => q.NewFile.Name)
            </td>
            <td>
                <input type="file" id="FileUploadField1" /></td>
            <td style="width: 16px; text-align: center;">&nbsp;</td>
        </tr>
        <tr>
            <td colspan="4" style="text-align: center;">
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
    <script type="text/javascript">

        $('.content-table .add-icon').click(function () {
            var lastFileField = $('.content-table input[type="file"]').last();
            var lastId = lastFileField.attr('id').replace(/\D*/g, '');
            lastId = parseInt(lastId) + 1;
            var newFields = '<tr>' +
                '<td>Name : </td>' +
                '<td><input data-val="true" data-val-length="Max chars is 100, Min chars is 3" data-val-length-max="100" data-val-length-min="3" data-val-required="Required" id="NewFile_Name' + lastId + '" name="NewFile.Name' + lastId + '" type="text" value="" /><br /><span class="field-validation-valid" data-valmsg-for="NewFile.Name' + lastId + '" data-valmsg-replace="true"></span></td>' +
                '<td><input type="file" id="FileUploadField' + lastId + '"/></td>' +
                '<td style="text-align:right;"><div class="delete-icon"></div></td>' +
                '</tr>';
            var lastTr = $(lastFileField).parents('tr:first')[0];
            $(lastTr).after(newFields);
        });

        $('.content-table .delete-icon').live('click', function () {
            $(this).parents('tr:first').remove();
        });
    </script>
}

As you can see, We have a form for uploading one or more files. So, I've added an + button for users that they can add a file field to form.

Users must enter the name of the file and select a file for uploading. But MVC client validator just validate the first inputs that added with Razor.

How can I force MVC validator to validate all fields at the client side and server side.

Another question is:
How can we handle getting the field values at a MVC Controller.

Thanks

like image 423
Mohammad Dayyan Avatar asked Oct 24 '12 12:10

Mohammad Dayyan


1 Answers

This great blog will help you understand how the default model binder will bind lists and arrays. Just make a ViewModel for your page that looks somewhat like this:

public class FileUploadViewModel
{
    public List<FileModel> lFileModels { get; set; }
}

Then in your "+" jQuery function, make sure the generated input names are something like lFileModels.[0].Title (or it might be lFileModels[0].Title, just click that link and you'll figure it out)

Then to get that info in the controller, it's just like any other form!

[HttpPost]
public ActionResult Index(FileUploadViewModel viewModel)
{

}

Edit

Another link for MVC file uploading

Edit 2

After reading your code once again, I now realise that the validation problem is due to adding unobtrusive validations after the library was loaded. You have to re-parse the validators.

$("form").data("validator", null);
$.validator.unobtrusive.parse($("form"));

The binding applies to server-side validation and the 2nd part of your question.

Edit 3

For adding fields, instead of doing it straight in JS, you should Ajax load the section of your form with the file fields. When you click on the add button, it request a partial view of the file fields with, in it's post data, a list of the current items. The partial view then returns a rendered view with an extra field. It's just an idea. I haven't tried or even seen that idea. I just though about it and figured I could share it.

like image 117
Pluc Avatar answered Oct 18 '22 23:10

Pluc