简体   繁体   中英

Modal Pop-Up Not Passing iFormFile Data On JavaScript Ajax Intercept

This is sort of an add-on to my previous question: Modal Pop-Up Not Closing Properly After Form Submission

I'm trying to reuse the modal pop-up functionality for another pop-up on the same page. This time I am using it to upload a file. This is the javascript in question:

$('body').on('click', '.relative', function (e) {
        e.preventDefault();
        var form = $(this).parents('.modal').find('form');
        var actionUrl = form.attr('action');
        var dataToSend = form.serialize();
        $.post(actionUrl, dataToSend).done(function (data) {
            $('body').find('.modal-content').html(data);
            var isValid = $('body').find('[name="IsValid"]').val() == 'True';
            if (isValid) {
                $('body').find('#modal-container').modal('hide');
                window.location.href = "/Issue/Edit";
            }

        });
    })

I inadvertently misspelled "relative" on the submit button of this form:

@model Models.AttachmentModel
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="@ViewData.ModelState.IsValid.ToString()" />

<!--Modal Header Start-->
<div class="modal-header">
    <h4 class="modal-title">Upload File</h4>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload"  method="post" enctype="multipart/form-data" asp-controller="Attachment">
    @Html.AntiForgeryToken()

    <div class="modal-body form-horizontal">
        <div>
            <p>Upload a file using this form:</p>
            <input type="file" name="file" />
            <span asp-validation-for="@Model.aFileData" class="text-danger"></span>
        </div>
        <div>
            <p>Enter a file description</p>
            <input id="attachment" asp-for="@Model.aIssueAttachmentDescription" class="form-control" />
            <span asp-validation-for="@Model.aIssueAttachmentDescription" class="text-danger"></span>
            <input id="issueid" type="hidden" asp-for="@Model.issueId" class="form-control" value="@ViewBag.id" />
        </div>

        <!--Modal Footer Start-->
        <div class="modal-footer">
            @*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*@
            <button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
            <input type="submit" class="btn btn-success realative" id="btnSubmit" data-save="modal" value="Upload">
        </div>
        <div class="row">
            &nbsp;
        </div>

    </div> <!--Modal Footer End-->
</form>

</div>
<script type="text/javascript">
    $(function () {

    });
</script>

With the word "relative" misspelled, the file information is being sent to the action in the controller(see below). My guess is the Javscript isn't catching the click action ($('body').on('click', '.relative', function (e)). When I spell "relative" correctly the file information is NULL:

  public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
    { //do something
    }

What needs to change with the Javascript (or my form/controller) to get the file information? In both cases the collection information is being passed. Is there a way to get the file information added to the collection?

--------- More Info based on @Rena answer Let me expand some more on the original code and how this works. I have a page that has a modal section that will be populated with different partial views depending upon what I want displayed in the modal. On the Main page it has the following Javascript section:

<script>
    $('body').on('click', '.modal-link', function () {
        var actionUrl = $(this).attr('href');
        $.get(actionUrl).done(function (data) {
            $('body').find('.modal-content').html(data);
        });
        $(this).attr('data-target', '#modal-container');
        $(this).attr('data-toggle', 'modal');
    });

    $('body').on('click', '.relative', function (e) {
        e.preventDefault();
        var form = $(this).parents('.modal').find('form');
        var actionUrl = form.attr('action');
        var dataToSend = form.serialize();
        $.post(actionUrl, dataToSend).done(function (data) {
            $('body').find('.modal-content').html(data);
            var isValid = $('body').find('[name="IsValid"]').val() == 'True';
            if (isValid) {
                $('body').find('#modal-container').modal('hide');
                window.location.href = "/Issue/Edit";
            }

        });
    })

    $('body').on('click', '.close', function () {
        $('body').find('#modal-container').modal('hide');
    });

    $('#CancelModal').on('click', function () {
        return false;
    });

    $("form").submit(function () {
        if ($('form').valid()) {
            $("input").removeAttr("disabled");
        }
    });
</script>

I took what was provided by @Rena and inserted it into this section, but found that the Modal wouldn't close (although the data from the form in the partial view was now getting passed). I tried changing the.realative to another value on both the partial view and the javascript, but it made no difference. I then tried what @mj313 suggested in the preceding posts by changing the provided script like this to redirect to /Issue/Edit but that didn't work either.:

               }).done((response, textStatus, xhr) => {
                $('body').find('.modal-content').html(data);
                var isValid = $('body').find('[name="IsValid"]').val() == 'True';
                if (isValid) {
                    $('body').find('#modal-container').modal('hide');
                    window.location.href = "/Issue/Edit";
                }
               });

So while I can now pass data I can't close the Modal.

Here is a slimmed down version of the Edit page where all of this starts

    @model MYAPP.ViewModels.IssueViewModel

@{
    ViewData["Title"] = "Issue Detail Page";
}

<script type="text/javascript">
    $(document).ready(function () {
        $("#UploadSection").load("/Attachment/GetAttachments/" + @Model.IssueData.issueId);
    });
    $(function () {        
            //Some code
    });
    function onSelectChange(element) {
     //Some code
    }
</script>

<div asp-validation-summary="All" class="text-danger"></div>
<hr />

<div class="row">
    <div>
        <form asp-action="Edit">
            <input type="hidden" asp-for="IssueData.issueId" />

                @*Some Code*@

            @*Placeholder for Modal Pop-up*@
            <div id="modal-container" class="modal fade" tabindex="-1">
                <div class="modal-dialog modal-lg">
                    <div class="modal-content">
                    </div>
                </div>
            </div>
            
            @*This table contains the first control that generates a modal which contains the _CreateEdit.cshtml*@
            <table width="100%">
                <tr>
                    <td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
                        <div class="form-group">
                            <label asp-for="IssueData.issueStatus" class="control-label">Current Issue Status</label>
                            &nbsp;&nbsp;&nbsp;- &nbsp;
                            @if (@Model.IssueData.StatusList[0].UpdatedByName != "")
                            {
                                <text>Updated by: </text> @Model.IssueData.StatusList[0].UpdatedByName <text> - </text>@Model.IssueData.StatusList[0].StatusDate.Value.ToShortDateString()
                            }
                            else
                            {
                                <text>Created by: </text> @Model.IssueData.StatusList[0].EnteredByName <text> - </text>@Model.IssueData.StatusList[0].StatusDate.Value.ToShortDateString()
                            }

                        </div>
                    </td>
                    <td style="background-color: midnightblue; padding-right:5px">
                        @if (@Model.IssueData.StatusList[0].StatusDate != DateTime.Today)
                        {
                            <a href="@Url.Action("CreateEdit", new { controller = "Issue", issueid = Model.IssueData.issueId, addedit = "add" })" class="modal-link btn btn-success">Add New Status</a>

                        }
                        else
                        {
                            <a href="@Url.Action("CreateEdit", new { controller = "Issue", issueid = Model.IssueData.issueId, addedit = "edit"  })"
                               class="modal-link btn btn-success">Edit Current Status</a>
                        }
                    </td>
                </tr>
            </table>                
            <br />
            @*This table contains the second control that generates a modal which contains the _UploadFile.cshtml*@
            <table id="upload" width="100%">
                <tr>
                    <td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
                        <label class="control-label">Upload Attachments</label>
                    </td>
                    <td style="background-color: midnightblue; padding-right:5px">
                        <a href="@Url.Action("FileUpload", new { controller = "Attachment", issueid = Model.IssueData.issueId  })"
                           class="modal-link btn btn-success">Upload Files</a>
                    </td>
                </tr>
            </table>
            @*This section contains a partial view _DisplayFiles.cshtml. The _DisplayFiles.cshtml has controls that generate 2 more modals. The modals contain either the 
            _DeleteFile.cshtml or _EditFile.cshtml partial views*@
            <div id="UploadSection"></div>
            @{
                await Html.RenderPartialAsync("_DisplayFiles");
            }              
            <div class="form-group">
                <input type="submit" value="Save Changes" class="btn btn-primary" />
            </div>
        </form>
    </div>

</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script>
        //Using this to scroll the page on the close of the modal/page refresh
         $(document).ready(function () {
            var JumpTo = '@ViewBag.JumpToDivId';
            if (JumpTo != "") {
                $(this).scrollTop($('#' + JumpTo).position().top);
            }
        });
        //Using this to Capture the click that opens the modals
        $('body').on('click', '.modal-link', function () {
            var actionUrl = $(this).attr('href');
            $.get(actionUrl).done(function (data) {
                $('body').find('.modal-content').html(data);
            });
            $(this).attr('data-target', '#modal-container');
            $(this).attr('data-toggle', 'modal');
        });
        //Using this to Capture the click that Submits the _EditFile,_DeleteFile,_CreateEdit forms on the modal
        $('body').on('click', '.relative', function (e) {
            e.preventDefault();
            var form = $(this).parents('.modal').find('form');
            var actionUrl = form.attr('action');
            var dataToSend = form.serialize();
            $.post(actionUrl, dataToSend).done(function (data) {
                $('body').find('.modal-content').html(data);
                var isValid = $('body').find('[name="IsValid"]').val() == 'True';
                var issueid = "";
                issueid = $('body').find('[name="issueidSaved"]').val();
                var jumpto = $('body').find('[name="jumpto"]').val();
                if (isValid) {
                    $('body').find('#modal-container').modal('hide');
                    if (issueid == "")
                    {
                        window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto=" + jumpto;
                    }
                }
            });
        })
        //Using this to Capture the click that Submits the _UploadFile form on the modal
        $(function () {
            $('body').on('click', '.fileupload', function (e) {
                e.preventDefault();
                var form = $(this).parents('.modal').find('form');
                var actionUrl = form.attr('action');

                var fdata = new FormData();
                $('input[name="file"]').each(function (a, b) {
                    var fileInput = $('input[name="file"]')[a];
                    if (fileInput.files.length > 0) {
                        var file = fileInput.files[0];
                        fdata.append("file", file);
                    }
                });
                $("form input[type='text']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $("form input[type='hidden']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $.ajax({
                    url: actionUrl,
                    method: "POST",
                    contentType: false,
                    processData: false,
                    data: fdata
                }).done((response, textStatus, xhr) => {
                    var isValid = $(response).find('[name="IsValid"]').val() == 'True';
                    var issueid = $(response).find('[name="issueidSaved"]').val();
                    var jumpto = $(response).find('[name="jumpto"]').val();
                    if (isValid) {
                        $('body').find('#modal-container').modal('hide');
                        window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto="+jumpto;
                    }
                   });
            })
        });

        $('body').on('click', '.close', function () {
            $('body').find('#modal-container').modal('hide');
        });

        $('#CancelModal').on('click', function () {
            return false;
        });

        $("form").submit(function () {
            if ($('form').valid()) {
                $("input").removeAttr("disabled");
            }
        });
    </script>
}

Here is the code for _UpdateFile.cshtml

    @model MYAPP.Models.AttachmentModel

<!--Modal Body Start-->

<div class="modal-content">
    <input name="IsValid" type="hidden" value="@ViewData.ModelState.IsValid.ToString()" />
    <input name="issueidSaved" type="hidden" value="@ViewBag.ID" />
    <input name="jumpto" type="hidden" value="@ViewBag.JumpToDivId" />
    <!--Modal Header Start-->
    <div class="modal-header">
        <h4 class="modal-title">Upload File</h4>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
    </div>
    <!--Modal Header End-->
    <form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Attachment">
        @Html.AntiForgeryToken()

        <div class="modal-body form-horizontal">
            <div>
                <p>Upload a file using this form:</p>
                <input type="file" name="file" />
                <span asp-validation-for="@Model.aFileData" class="text-danger"></span>
            </div>
            <div>
                <p>Enter a file description</p>
                <input id="attachment" asp-for="@Model.aIssueAttachmentDescription" class="form-control" />
                <span asp-validation-for="@Model.aIssueAttachmentDescription" class="text-danger"></span>
                <input id="issueid" type="hidden" asp-for="@Model.issueId" class="form-control" value="@ViewBag.id" />
            </div>

            <!--Modal Footer Start-->
            <div class="modal-footer">
                @*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*@
                <button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
                <input type="submit" class="btn btn-success fileupload" id="btnSubmit" data-save="modal" value="Upload">
            </div>
            <div class="row">
                &nbsp;
            </div>

        </div> <!--Modal Footer End-->
    </form>

</div>
<script type="text/javascript">
    $(function () {

    });
</script>

<!--Modal Body End--> 

Here is the code for the file Upload

   [HttpPost]
public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
{
    if (file == null)
    {
        ModelState.AddModelError("aFileData", "Please select a file.");
    }
    if (collection["aIssueAttachmentDescription"] == "")
    {
        ModelState.AddModelError("aIssueAttachmentDescription", "Please provide a description for the file.");
    }

    if (!ModelState.IsValid)
    {
        return PartialView("_UploadFile");
    }

    var formFileContent =
        await FileHelpers.ProcessFormFile<BufferedSingleFileUploadDb>(
            file, ModelState, _permittedExtensions,
            _fileSizeLimit);

    var thefile = new AttachmentModel
    {
        aFileData = formFileContent,
        aFileName = file.FileName,
        aIssueAttachmentDescription = collection["aIssueAttachmentDescription"],
        aFileSize = file.Length,
        aFileType=file.ContentType,
        issueId = collection["issueId"]
    };
    string result = _adoSqlService.InsertFile(thefile);
    ViewBag.ID = collection["issueId"];
    ViewBag.JumpToDivId = "upload";
    return PartialView("_UploadFile");
}

You can see in the code above that I add in model errors if the file is not selected or the description is not filled in. These are not being shown.

I can live with the collection returning the entire Edit forms data, but it should only return the fields on the _UploadFile.cshtml form (aIssueAttachmentDescription, issueId)它应该只返回 _UploadFile.cshtml 表单上的字段(aIssueAttachmentDescription,issueId)

Anything you can provide that fixes the display of the model errors as well as a way to simplify my code would be greatly appreciated.

With the word "relative" misspelled, the file information is being sent to the action in the controller(see below). My guess is the Javscript isn't catching the click action ($('body').on('click', '.relative', function (e)). When I spell "relative" correctly the file information is NULL

The <input type="submit"> defines a submit button which submits all form values to a form-handler.So although you misspelled the word,it also could submit to the action successfully by default.

For how to use ajax to pass form data with file,you could follow:

    @model Mvc3_0.Controllers.HomeController.AttachmentModel
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
    Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog" role="document">
        <!--Modal Body Start-->
        <div class="modal-content">
            <input name="IsValid" type="hidden" value="@ViewData.ModelState.IsValid.ToString()" />

            <!--Modal Header Start-->
            <div class="modal-header">
                <h4 class="modal-title">Upload File</h4>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
            </div>
            <!--Modal Header End-->
            <form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Attachment">
                @Html.AntiForgeryToken()

                <div class="modal-body form-horizontal">
                    <div>
                        <p>Upload a file using this form:</p>
                        <input type="file" name="file" />
                        <span asp-validation-for="@Model.aFileData" class="text-danger"></span>
                    </div>
                    <div>
                        <p>Enter a file description</p>
                        <input id="attachment" asp-for="@Model.aIssueAttachmentDescription" class="form-control" />
                        <span asp-validation-for="@Model.aIssueAttachmentDescription" class="text-danger"></span>
                        <input id="issueid" type="hidden" asp-for="@Model.issueId"  class="form-control" value="@ViewBag.id" />
                    </div>

                    <!--Modal Footer Start-->
                    <div class="modal-footer">
                        @*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*@
                        <button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
                        <input type="submit" class="btn btn-success realative" id="btnSubmit" data-save="modal" value="Upload">
                    </div>
                    <div class="row">
                        &nbsp;
                    </div>

                </div> <!--Modal Footer End-->
            </form>

        </div>
    </div>
</div>
@section Scripts
{
    <script type="text/javascript">
        $(function () {
            $('body').on('click', '.realative', function (e) {
                e.preventDefault();
                var form = $(this).parents('.modal').find('form');
                var actionUrl = form.attr('action');

                var fdata = new FormData();
                $('input[name="file"]').each(function (a, b) {
                    var fileInput = $('input[name="file"]')[a];
                    if (fileInput.files.length > 0) {
                        var file = fileInput.files[0];
                        fdata.append("file", file);                        
                    }
                });
                $("form input[type='text']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $("form input[type='hidden']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $.ajax({
                    url: actionUrl,
                    method: "POST",
                    contentType: false,
                    processData: false,
                    data: fdata
                }).done((response, textStatus, xhr) => {
                        $("#exampleModal").modal('hide'); //update here...
                   });  
            })
        });
    </script>
}

Update1:

.done((response, textStatus, xhr) => {
        $("#exampleModal").modal('hide'); //update here...
}); 

Update2:

By using your code,I find that you add the modal html in a form which is in the main page.This will cause the form in modal which is in _UploadFile.cshtml could not generate well in my project.Here is the whole working demo:

Main Page:

@model AttachmentModel
<div class="row">
    <div>
        //change here.....

        <div id="modal-container" class="modal fade" tabindex="-1">
            <div class="modal-dialog modal-lg">
                <div class="modal-content">
                </div>
            </div>
        </div>

        <form asp-action="Edit">
            <br />
            @*This table contains the second control that generates a modal which contains the _UploadFile.cshtml*@
            <table id="upload" width="100%">
                <tr>
                    <td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
                        <label class="control-label">Upload Attachments</label>
                    </td>
                    <td style="background-color: midnightblue; padding-right:5px">
                        <a href="@Url.Action("FileUpload", new { controller = "Attachment", issueid = "1"  })"
                           class="modal-link btn btn-success">Upload Files</a>
                    </td>
                </tr>
            </table>

            <div class="form-group">
                <input type="submit" value="Save Changes" class="btn btn-primary" />
            </div>
        </form>
    </div>

</div>

Js in Main Page:

@section Scripts
{
    <script type="text/javascript">
        $(function () {
            $('body').on('click', '.modal-link', function () {
                var actionUrl = $(this).attr('href');
                $.get(actionUrl).done(function (data) {
                    $('body').find('.modal-content').html(data);
                });
                $(this).attr('data-target', '#modal-container');
                $(this).attr('data-toggle', 'modal');
            });


            $('body').on('click', '.fileupload', function (e) {
                e.preventDefault();
                var form = $(this).parents('.modal').find('form');
                var actionUrl = form.attr('action');
                console.log(actionUrl);
                var fdata = new FormData();
                $('input[name="file"]').each(function (a, b) {
                    var fileInput = $('input[name="file"]')[a];
                    if (fileInput.files.length > 0) {
                        var file = fileInput.files[0];
                        fdata.append("file", file);

                    }
                });
                $("form input[type='text']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $("form input[type='hidden']").each(function (x, y) {
                    fdata.append($(y).attr("name"), $(y).val());
                });
                $.ajax({
                    url: actionUrl,
                    method: "POST",
                    contentType: false,
                    processData: false,
                    data: fdata
                })
                    .done((response, textStatus, xhr) => {
                        var isValid = $(response).find('[name="IsValid"]').val() == 'True';
                        var issueid = $(response).find('[name="issueidSaved"]').val();
                        var jumpto = $(response).find('[name="jumpto"]').val();
                        if (isValid) {
                            $('body').find('#modal-container').modal('hide');
                        }
                    });
            })
        })
    </script>
}

_UploadFile.cshtml:

@model AttachmentModel
    
<div class="modal-content">
    <input name="IsValid" type="hidden" value="@ViewData.ModelState.IsValid.ToString()" />
    <input name="issueidSaved" type="hidden" value="@ViewBag.ID" />
    <input name="jumpto" type="hidden" value="@ViewBag.JumpToDivId" />
    <!--Modal Header Start-->
    <div class="modal-header">
        <h4 class="modal-title">Upload File</h4>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
    </div>
    <!--Modal Header End-->
    <form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Home">
        @Html.AntiForgeryToken()

        <div class="modal-body form-horizontal">
            <div>
                <p>Upload a file using this form:</p>
                <input type="file" name="file" />
                <span asp-validation-for="@Model.aFileData" class="text-danger"></span>
            </div>
            <div>
                <p>Enter a file description</p>
                <input id="attachment" asp-for="@Model.aIssueAttachmentDescription" class="form-control" />
                <span asp-validation-for="@Model.aIssueAttachmentDescription" class="text-danger"></span>
                <input id="issueid" type="hidden" asp-for="@Model.issueId" class="form-control" value="@ViewBag.id" />
            </div>

            <!--Modal Footer Start-->
            <div class="modal-footer">
                @*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*@
                <button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
                <input type="submit" class="btn btn-success fileupload" id="btnSubmit" data-save="modal" value="Upload">
            </div>
            <div class="row">
                &nbsp;
            </div>

        </div> <!--Modal Footer End-->
    </form>
</div>

Controller:

[HttpPost]
public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
{
    var thefile = new AttachmentModel
    {
        aFileData = "asdad",
        aIssueAttachmentDescription = collection["aIssueAttachmentDescription"],
        issueId = collection["issueId"]
    };
    ViewBag.ID = collection["issueId"];
    ViewBag.JumpToDivId = "upload";
    return PartialView("_UploadFile");
}

Result:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM