0

I am building an application that requires a user to answer a survey. I have built the survey to work with questions that are multiple choice questions; however, I am having trouble with doing the same with free-response questions.

This is my form in the view:

@using (Html.BeginForm("Submit", "Survey", FormMethod.Post, new { role = "form" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary("", new { @class = "text-danger" })
    var questionNumber = 0;
    <h4>Matchmaking Questions</h4>
    foreach (var question in Model.Questions)
    {
        var answers = Model.Answers.Where(a => a.QuestionId == question.Id);
        var answerList = new List<Answer>();

        <div class="form-group">
            <h5>
                <i>Q #@(questionNumber + 1)</i>: 
                @if (question.SurveyId == 3)
                {
                    if (User.IsInRole(UserType.HOST_ROLE))
                    {
                        <span>@question.Text</span>
                    }
                    else
                    {
                        <span>@question.Text2</span>
                    }
                }
                else
                {
                    <span>@question.Text</span>
                }
            </h5>
            <!-- If a question has a comment, display it here -->
            @if (!question.Comment.IsNullOrWhiteSpace())
            {
                <h6>@question.Comment</h6>
            }

            @if (answers.ToList().Any())
            {
                answerList = answers.ToList();
                @Html.DropDownListFor(m => m.UserAnswerIds[questionNumber],
                    new SelectList(answerList, "Id", "Text"),
                    "Select your answer", new { @class = "form-control" })
            }
            else
            {
                // TextAnswers has the correct number of count here...
                // But the values are not updated...
                Model.TextAnswers.Add(questionNumber, "");
                @Html.TextAreaFor(m => m.TextAnswers[questionNumber], 5, 300, new { })
            }
        </div>
        questionNumber++;
    }
<div class="form-group">
    <div class="col-md-offset-5 col-md-12">
        <input type="submit" class="btn btn-primary" value="Submit" />
    </div>
</div>
}

This is my View Model:

public class SurveyViewModel
{
    public IEnumerable<Question> Questions { get; set; }
    public IEnumerable<Answer> Answers { get; set; }
    public ApplicationUser User { get; set; }
    public int[] UserAnswerIds { get; set; }
    public Dictionary<int, string> TextAnswers { get; set; }
}

And this is my action that submits the form:

public ActionResult Submit(SurveyViewModel viewModel)
{
    var userAnswerIds = viewModel.UserAnswerIds;
    var userId = User.Identity.GetUserId();
    var surveyComplete = true;
    // Create a new answer based on user's text
    foreach (var textAnswer in viewModel.TextAnswers) 
    // viewModel.TextAnswers has count of 0 here...
    {
        var customAnswer = new Answer()
        {
            QuestionId = textAnswer.Key,
            Text = textAnswer.Value
        };
        try
        {
            customAnswer = _context.Answers.Add(customAnswer);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        // Add the new custom answer to user's list of answers
        userAnswerIds[textAnswer.Key] = customAnswer.Id;
    }

    // Add each answer to UserAnswer
    foreach (var t in userAnswerIds)
    {
        var currentAnswerBlock = t;
        if (_context.Answers.Any(a => a.Id == currentAnswerBlock))
        {
            var ua = new UserAnswer()
            {
                ApplicationUserId = userId,
                AnswerId = t
            };
            try
            {
                _context.UserAnswers.Add(ua);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        else
        {
            surveyComplete = false;
        }
   }

  // Update user's survey completion status
   try
   {
        _context.Users.Single(u => u.Id == userId).SurveyComplete = surveyComplete;
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
    _context.SaveChanges();

    return RedirectToAction("Index", "Profile");
}

The problem I am having is that when I am trying to work with the TextAnswer dictionary within the controller, the dictionary seems to be empty for some reason. When I tried debugging, the dictionary works within the View the "TextAreaFor" method does not seem to be updating the values of the dictionary. However, during the rendering of the view, the dictionary is there and there are entries created for each of the text answers: it's just that the values don't update nor get passed into the controller along with the view model.

I am completely stumped and would love some guidance from professionals.

nugget
  • 11
  • 4
  • From what I see for `Dictionary` bindings, they're usually using `foreach` loop with `Dictionary` as iteration base, e.g. `@foreach (var answer in TextAnswers) { Html.TextAreaFor(m => m.TextAnswers[answer.Key], 5, 300, new { }}`. You may consider using partial view to bind `SurveyViewModel.Answers` separately from question view (check https://stackoverflow.com/questions/10555917/mvc3-dictionary-not-binding-to-model for similar construction). – Tetsuya Yamamoto May 31 '17 at 02:27
  • It actually seems to be a different problem. Only part of the answers are sent to the controller. I have a total of 30 questions for a user, but when I receive the SurveyViewModel in the controller, the model's userAnswerIds is size of 9??!? When the view is rendered, the size is 30... this makes no sense to me.. – nugget May 31 '17 at 03:17

0 Answers0