Febin J S
Febin J S

Reputation: 1368

Post a list property along with other model properties in JQuery Ajax to MVC controller?

today i have a requirement where i have to submit a user's education details to the db. First of all i will explain from the entities, i have a one to many relation between the user and Education table, ie a user can can have multiple education details.

My EducationalBackground model looks like this

public class EducationalBackground
{
    public int EducationalBackgroundID { get; set; }

    public string UniversityOrCollege { get; set; }

    public string AreaOfStudy { get; set; }

    public string Degree { get; set; }

    public string YearReceived { get; set; }
}

My Instructor Model which is my main model looks like this which contains a list of EducationBackground.

public class InstructorApplicationViewModel
    {
        public InstructorApplicationViewModel()
        {
            EducationalBackgrounds = new List<EducationalBackGround>
            {            
                new EducationalBackGround {
                AreaOfStudy = string.Empty,
                Degree = string.Empty,
                UniversityOrCollege = string.Empty,
                YearReceived = string.Empty
                }
            };
        }

        public IList<EducationalBackGround> EducationalBackgrounds { get; set; }

        public int CurrentUserId { get; set; } 

        [Required]
        public string Experience { get; set; }

        [Required]
        public bool WillingToTravel { get; set; }
    }

My view looks like this

@model PaulSchool.ViewModels.InstructorApplicationViewModel
@{
    ViewBag.Title = "ApplyToBecomeInstructor";
}
<h2>
    ApplyToBecomeInstructor</h2>
<script src="@Url.Content("~/Scripts/EducationalBackgroundListEditor.js")" type="text/javascript"> </script>
@using (Html.BeginForm())
{
    <fieldset>
        <legend>ApplyToBecomeInstructor</legend>
        <div class="editor-label">
            <p>
                Information from your user profile will be considered when applying to become an
                Instructor</p>
        </div>
        @Html.HiddenFor(model => model.CurrentUserId)
        <div class="editor-label">
            @Html.LabelFor(model => model.EducationalBackgrounds)
        </div>
        <div id="editorRows">
            @Html.EditorFor(model => model.EducationalBackgrounds)
        </div>
        @Html.ActionLink("Add additional educational background.", "EducationalBackground", null, new { id = "addItem" })
        <div class="editor-label">
            @Html.LabelFor(model => model.Experience)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Experience)
        </div>
        <div class="editor-label">
            Are you willing to travel?
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.WillingToTravel)
        </div>
        <p>
            <input type="submit" value="Create" id="btnSubmit" />
        </p>
        <div class="newRow" style="display: none;">
            <div class="editorRow">
                <p>
                    <label>
                        UniversityOrCollege</label>
                    <input class="university" type="text" value="" />
                </p>
                <p>
                    <label>
                        AreaOfStudy</label>
                    <input class="area" type="text" value="" />
                </p>
                <p>
                    <label>
                        Degree</label>
                    <input class="degree" type="text" value="" />
                </p>
                <p>
                    <label>
                        YearReceived</label>
                    <input class="year" type="text" value="" />
                </p>
                <div>
                    <a href="javascript:void(0);" class="deleteRow">Delete</a>
                </div>
            </div>
        </div>
    </fieldset>
}
<div>
    @Html.ActionLink("Back", "Index")
</div>

I have included a editor template in the Views/Shared/EditorTemplate folder to include the educationbackground details, which will act as a partial view as well as EditorTemplate

@model PaulSchool.ViewModels.EducationalBackGround
<div class="editorRow">
        <p>
            @Html.LabelFor(model => model.UniversityOrCollege)
            @Html.TextBoxFor(model => model.UniversityOrCollege, new { @class="university" })
        </p>
        <p>
            @Html.LabelFor(model => model.AreaOfStudy)
            @Html.TextBoxFor(model => model.AreaOfStudy, new { @class="area" })
        </p>
        <p>
            @Html.LabelFor(model => model.Degree)
            @Html.TextBoxFor(model => model.Degree, new { @class = "degree" })
        </p>
        <p>
            @Html.LabelFor(model => model.YearReceived)
            @Html.TextBoxFor(model => model.YearReceived, new { @class = "year" })
        </p>
    <div>
        <a href="javascript:void(0);" class="deleteRow">Delete</a>
    </div>
</div>

I have a written a JQuery script like this tho post the values to the controller and was able to post everything to the model except the list of background details

<script type="text/javascript">
    $('#btnSubmit').click(function () {
        instructorUrl = '@Url.Action("ApplyToBecomeInstructor", "InstructorApplication")';
        var user = [];
        var educationList = [];
        var currentUser = '@Model.CurrentUserId';
        var experience = $('#Experience').val();
        var isWilling = $('#WillingToTravel').is(":checked");
        $('#editorRows .editorRow').each(function () {
            var education = {
                UniversityOrCollege: $(this).find('.university').val(),
                AreaOfStudy: $(this).find('.area').val(),
                Degree: $(this).find('.degree').val(),
                YearReceived: $(this).find('.year').val()
            }
            educationList.push(education);
        });
        var applicationFromView = {
            EducationalBackgrounds: educationList,
            CurrentUserId: currentUser,
            Experience: experience,
            WillingToTravel: isWilling
            }
    $.ajax({
        type: 'POST',
        url: instructorUrl,
        dataType: "json",
        data: applicationFromView,
        success: function (data) {
        },
        error: function (a, b, c) {
            alert('A problem ocurred');
        }
    });
});

</script>

Also my controller looks like this

[HttpPost]
public ActionResult ApplyToBecomeInstructor(InstructorApplicationViewModel applicationFromView)
{
    Student thisStudent = this.db.Students.FirstOrDefault(o => o.StudentID == applicationFromView.CurrentUserId);
    var instructorApplication = new InstructorApplication
        {
            BasicInfoGatheredFromProfile = thisStudent, 
            EducationalBackground = applicationFromView.EducationalBackgrounds as ICollection<EducationalBackground>, 
            Experience = applicationFromView.Experience, 
            WillingToTravel = applicationFromView.WillingToTravel
        };
    this.db.InstructorApplication.Add(instructorApplication);
    this.db.SaveChanges();
    return this.Redirect("Index");
}

I Know that the problem is with my Jquery script, but i am totally confused now, can anybody please take a look and help me?

Upvotes: 1

Views: 2087

Answers (1)

nemesv
nemesv

Reputation: 139818

Two things I've noticed in the first round.

  • Your are setting dataType: "json" but dataType is the type of data that you're expecting back from the server, not what your sending. You need to set contentType
  • You need to JSON.stringify the data to make the modelbinder happy.

Based on the above two your ajax call should like this:

$.ajax({
        type: 'POST',
        url: instructorUrl,
        dataType: "json",
        data: JSON.stringify(applicationFromView),  //<-- JSON.stringify
        contentType: 'application/json; charset=utf-8', //<-- contentType
        success: function (data) {
        },
        error: function (a, b, c) {
            alert('A problem ocurred');
        }
    });

Upvotes: 2

Related Questions