ASP.NET MVC - jQuery POST method is null

By : klaydze
Source: Stackoverflow.com
Question!

I'm calling a PartialView and injected it to a <div> from another PartialView to make it popup modal using Boostrap Modal. So far, my Boostrap Modal is displaying as expected BUT, NOT behaving as expected. The following are my objectives in my Boostrap Modal.

  1. Make a Boostrap Modal - OK
  2. Add validation on the Boostrap Modal - OK
  3. Send the value of my modal to save in the database - NOT OK

This is the <div> where I inject the PartialView and make it a modal

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">Create Sample</h4>
        </div>
        <div class="modal-body">
            <div id="modalBodyContainer">

            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary" id="btnCreateSample">Create</button>
        </div>
    </div>
</div>

PartialView to show as Boostrap Modal (This will be injected in the above <div>)

@model WebSensoryMvc.Models.SampleData

 @using (Html.BeginForm("Create", "SessionData", FormMethod.Post, new { id = "FormCreateSample", name = "FormCreateSample" }))
 {
@Html.AntiForgeryToken()

<div class="container">
    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.GroupNo, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.GroupNo, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.GroupNo, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.MaterialID, "Material", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("MaterialID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.MaterialID, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.SampleCode, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.SampleCode, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.SampleCode, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.BatchCode, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.BatchCode, new { htmlAttributes = new { @class = "form-control text-uppercase" } })
                    @Html.ValidationMessageFor(model => model.BatchCode, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.SizeID, "Size", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("SizeID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.SizeID, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.AgeID, "Age", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("AgeID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.AgeID, "", new { @class = "text-danger" })
                </div>
            </div>

        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.TemperatureID, "Temperature", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("TemperatureID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.TemperatureID, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.PackagingTypeID, "Packaging Type", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("PackagingTypeID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.PackagingTypeID, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.Spike, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    <div class="checkbox">
                        @Html.EditorFor(model => model.Spike)
                        @Html.ValidationMessageFor(model => model.Spike, "", new { @class = "text-danger" })
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.SampleType, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.SampleType, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.SampleType, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="row">
            <div class="form-group">
                @Html.LabelFor(model => model.Remarks, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Remarks, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Remarks, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>
    </div>
</div>
 }

Currently, I'm having hard time debugging in saving the modal value in the database. I'm using ajax to call a method in a controller. But, I'm experiencing the following problems.

  1. When the below code is executed, the $('#FormCreateSample').serialize() which expected to return the model of the PartialView is blank, where all the properties are null.

      $(document).ready(function () {
         $("#btnModal").on('click', function () {
        var url = "/SessionData/Create";
    
        $.ajax({
            url: url,
            type: 'GET',
            success: function (data) {
                $('#modalBodyContainer').html(data)
                $('#myModal').modal('show');
    
                $("#btnCreateSample").off().on('click', function () {
    
                    var form = $('form');
    
                    form.data('validator', null);
                    $.validator.unobtrusive.parse(form);
    
                    if ($('form').valid()) {
    
                        $.ajax({
                            url: "/SessionData/Create",
                            type: "POST",
                            data: $('#FormCreateSample').serialize(),
                            success: function () {
                                alert("POST success");
                            },
                            error: function () {
                                alert("POST error");
                            }
                        });
    
                    }
                });
            }
        });
    });
     });
    
  2. Since my action method in controller have [ValidateAntiForgeryToken] annotation, the above script throw an exception "Token is not present...". To fix that, I updated my code and add the below lines of code.

     var token = $('input[name="__RequestVerificationToken"]').val();
      $.ajax({
         url: "/SessionData/Create",
         type: "POST",
         data: { $('#FormCreateSample').serialize(), __RequestVerificationToken: token },
        success: function () {
           alert("POST success");
        },
        error: function () {
            alert("POST error");
        }
     });
    

The problem in # 2 approach is, it passes null value in my action method sampleData parameter. Below is my action method in my controller.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public void Create(SampleData sampleData)
    {
        if (ModelState.IsValid)
        {
            sampleData.SessionID = Convert.ToInt32(TempData["CurrentSessionId"]);

            db.SampleDatas.Add(sampleData);
            db.SaveChanges();

            RedirectToAction("List", "SessionData");
        }

    }

Anyone have an idea why $("FormCreateSample").serialize() is null? Or maybe it cannot find the form id FormCreateSample?

TIA

UPDATE 1 After using the first answer, the model is now pass to method but all properties are still null.

enter image description here

By : klaydze


Answers

You need to add AntiForgeryToken in your message header in the ajax call:

var token = $('input[name="__RequestVerificationToken"]').val();
var tokenadr = $('form[action="/SessionData/Create"] input[name="__RequestVerificationToken"]').val(); 

var headers = {};
var headersadr = {};
headers['__RequestVerificationToken'] = token;
headersadr['__RequestVerificationToken'] = tokenadr;

 $.ajax({
 url: "/SessionData/Create",
 type: "POST",
 headers: headersadr,
 data: "__RequestVerificationToken="   token   ""   $('form[action="/SessionData/Create"]').serialize(),
success: function () {
   alert("POST success");
},
error: function () {
    alert("POST error");
}
});
By : Developer


Try changing

.serialize()

To

.serializeArray()
By : Emil


var token = $('input[name="__RequestVerificationToken"]').val();
  $.ajax({
     url: "/SessionData/Create",
     type: "POST",
     data: { $('#FormCreateSample').serialize(), __RequestVerificationToken: token },
     content-type : 'application/json',
    success: function () {
       alert("POST success");
    },
    error: function () {
        alert("POST error");
    }
 });

ADD this : content-type : 'application/json',



This video can help you solving your question :)
By: admin