1

I've looked for a couple hours now, hoping not to duplicate a question, and I just can't find what I'm looking for.

I am working on passing a complex object back from a form to a controller, and having it parse everything out. The problem I get is the controller shows a null input, despite the header post from Chrome showing the data going out. Can anyone give me a hand? I've included code below.

Model

public class QuizTakenObject
    {
        [NotMapped]
        public QuizTakenComplete quizTakenComplete { get; set; }

        [NotMapped]
        public List<QuizSubmittedAnswers> submittedAnswers { get; set; }

        [NotMapped]
        public TopicList Topic { get; set; }

        [NotMapped]
        public QuizHeader QuizHeader { get; set; }

    }

View/Script

@model App.Models.QuizTakenObject

@{
    ViewBag.Title = "Take Quiz";
}

@section pageScripts{
    <script type="text/javascript">
        $(document).ready(function () {

            //Highlight background of selected background for increased visibility
            $("input[name^=QuizSubmittedAnswer]").change(function () {
                $(this).parent().addClass("bg-primary");
                $(this).parent().siblings().removeClass("bg-primary");
            });

            //Show save prompt on page after one answer is picked
            var i = 0;
            if (i == 0) {
                $("input[name^=QuizSubmittedAnswer]").change(function () {

                    $("#quizSave").fadeIn('fast');
                    $("#quizSave").animate({ height: '125px' }, 'fast')
                                  .animate({ width: '250px' }, 'fast', function () {
                                  $("#quizSaveText").fadeIn('500');
                        });

                });

            }

            //Prevent submitting before all answers have been selected
            //Count all questions, one per form group
            var questionsCount = $("form-group").length;

            //Listen for answers to be selected
            $("input[name^=QuizSubmittedAnswer]").change(function () {
                //Check to see if all answers are selected
                if ($("input[name^=QuizSubmittedAnswer]:checked").length >= questionsCount) {
                    $("#saveAndSubmitQuizButton").removeClass("disabled");
                }

            });

            //Save and submit quiz
            $("#saveAndSubmitQuizButton").click(function () {
                event.preventDefault;

                var complete = true;

                saveQuizAttempt(complete);
            });

            //Save but not submit quiz
            $("#saveQuizOnlyButton").click(function () {
                event.preventDefault;

                var complete = false;

                saveQuizAttempt(complete);
            });

            //Create or update quiz attempt in DB
            //saveQuizAttempt complete indicates if the record is to be marked as final
            function saveQuizAttempt(complete) {

                var array = $("#takeQuizForm").serializeArray();

                //build JSON array
                var json = {};

                $.each(array, function () {
                    json[this.name] = this.value || '';
                })
                //array.push({ "IsComplete": complete });


                //AJAX to post data
                $.ajax({
                    type: "POST",
                    url: "SubmitQuiz",
                    data: JSON.stringify(array),
                    dataType: "json",
                    contentType:"application/json; charset=UTF-8",

                    success: function (data) {
                        console.log("Success!");
                    },

                    error: function () {
                        console.log("Error");
                    }
                });
            }


        });
    </script>
}

<style>
    #quizSave {
        display: none;
        position: fixed;
        z-index: 999;
        height: 0;
        width: 0;
        bottom: 100px;
        right: 0;
        background-color: khaki;
        border: 1px solid black;
        border-radius: 2px 2px 2px 2px;
        padding: .5em 1em .5em 1em;
    }
</style>

<h2>@ViewBag.TopicName Quiz</h2>

<div class="row">
    <div class="container col-xs-9 col-sm-9 col-md-9 col-lg-9">
        <div class="well well-sm">
            <strong>Directions:</strong> @Model.QuizHeader.QuizSummary
        </div>

        @using (Html.BeginForm("SubmitQuiz", "Quiz", FormMethod.Post, new { id = "takeQuizForm" }))
        {
            @Html.AntiForgeryToken()

            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            @Html.HiddenFor(model => model.QuizHeader.QuizID)
            @Html.HiddenFor(model => model.QuizHeader.TopicID);
            <input type="hidden" name="QuizTakenComplete.UserID" id="QuizTakenComplete.UserID" value="@(ViewBag.UserID)" />
            <input type="hidden" name="QuizTakenComplete.IsComplete" id="QuizTakenComplete.IsComplete" value="false" />

            <!--Questions/Answers-->

            for (int i = 0; i < @Model.QuizHeader.QuizQuestions.Count(); i++)
            {
                <div class="quizQuestionBlock@(i)">
                    <hr />
                    <h4>@Model.QuizHeader.QuizQuestions.ElementAt(i).Question</h4>
                    <form-group>
                        <input type="hidden" name="QuizSubmittedAnswers[@(i)].QuestionID" id="QuizSubmittedAnswers[@(i)].QuestionID" value="@(Model.QuizHeader.QuizQuestions.ElementAt(i).QuestionID)">
                        @{for (int j = 0; j < Model.QuizHeader.QuizQuestions.ElementAt(i).QuizAnswers.Count(); j++)
                        {

                        <!--answers via radio buttons-->
                            <div id="answer@(j)@(i)" class="quizAnswer@(j)">
                                <input type="radio" class="individualQuizAnswer" name="QuizSubmittedAnswers[@(i)].AnswerID" value="@Model.QuizHeader.QuizQuestions.ElementAt(i).QuizAnswers.ElementAt(j).AnswerID"> @Model.QuizHeader.QuizQuestions.ElementAt(i).QuizAnswers.ElementAt(j).Answer
                            </div>

                        }

                        }
                    </form-group>
                </div>
            }
            <hr />
            <button class="btn btn-success btn-block disabled" id="saveAndSubmitQuizButton" type="button">submit quiz</button>
            <div style="text-align:center;">
                <small> Submitting quiz will finalize this attempt and update your score records.</small>
            </div>
            <br />
            <br />

        }

    </div>


    <!--Sidebar-->
    <div class="container col-xs-3 col-sm-3 col-md-3 col-lg-3">
        <div class="panel panel-default">
            <div class="panel-heading collapsable">
                <h5><span class="glyphicon glyphicon-cog"></span> Actions</h5>
            </div>
            <div class="panel-body">
                <span class="glyphicon glyphicon-backward"></span> @Html.ActionLink("return to library", "Index", new { controller = "Library" })<br />
                @Html.ActionLink("cancel/go home", "Index", new { controller = "Home" }, new { @style = "color:red;" })
            </div>
        </div>
    </div>

    <!--Quiz Save/Quit-->
    <div id="quizSave">
        <div id="quizSaveText" style="display:none;">
            Save current answers and return to App training/quiz library?<br />
            <button type="button" id="saveQuizOnlyButton" class="btn btn-success">yes</button>
            <button type="button" data-toggle="tooltip" class="btn btn-danger" title="this will cancel all previous work without saving and return to the main menu">no</button>
            <br />
            <small>You will be able to return later to resume your work.</small>
        </div>
    </div>
</div>

Controller

//POST: Quiz/SubmitQuiz
[HttpPost]
public async Task<ActionResult> SubmitQuiz(string quizObject)
{
    //Send false value for complete in AJAX call, just parse based on this
    //Two starting JS scripts, which flow into a unified function

    var input = new JavaScriptSerializer().Deserialize<QuizTakenObject>(quizObject);

    var quizTakenComplete = new QuizTakenComplete
    {
        UserID = input.quizTakenComplete.UserID,
        IsComplete = input.quizTakenComplete.IsComplete,
        LastUpdate = DateTime.Now
    };

    //Parse if complete for purposes of updating records.
    if (quizTakenComplete.UserID != null || quizTakenComplete.UserID != "")
    {
        db.QuizTakenComplete.Add(quizTakenComplete);
        await db.SaveChangesAsync();

        var quizAttemptID = quizTakenComplete.QuizAttemptID;

        //Now Add Each Answer

        var quizTaken = new QuizSubmittedAnswers();
        quizTaken.QuizAttemptID = quizAttemptID;
        quizTaken.TopicID = input.Topic.TopicID;
        quizTaken.QuizID = input.QuizHeader.QuizID;



        return Content("Saved");
    }

    else
    {
        return Content("Not Saved");
    }

 }
2

1 Answer 1

3

I think that the problem is in Ajax Call you didn't specify the attribute name try with this

$.ajax({
                type: "POST",
                url: "SubmitQuiz",
                data: {quizObject : JSON.stringify(array)},
                dataType: "json",
                contentType:"application/json; charset=UTF-8",

                success: function (data) {
                    console.log("Success!");
                },

                error: function () {
                    console.log("Error");
                }
            });
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.