-1

So I am creating a survey monkey, a Survey Has 4 categories, and each category has 5 questions, the HomeController Index passes on the 20 questions from the Questions entity and each Questions must have a Range Slider with values from one to 5, the form values must be collected into a method in the controller, then accumulated into the QuestionResults table and processed, then they must be passed onto the CategoryResults and each Category, out of the 4, must have an accumulated score, they must then be compared to the CategoryFeedback(which is static) table and display the correct information. The code for my HomeController and it's index is as below.

The main issue that I am having, is that since I am passing on the form values through as a parameter of FormCollection, I am struggling to keep the relationship of a Question belonging to a Category and then passing these all onto the CategoryResult table for processing.

Any help will be greatly appreciated

Models:

Question

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace STRA.Models
{
    public class Question
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string CreatedBy { get; set; }
        public DateTime? DateCreated { get; set; }
        public DateTime? DateModified { get; set; }
        public virtual Category Category { get; set; }
        public int CategoryId { get; set; }
        public virtual ICollection<QuestionResult> QuestionResult { get; set; }
        public virtual ICollection<QuestionFeedback> QuestionFeedback { get; set; }
    }
}

QuestionResult

using IdentitySample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace STRA.Models
{
    public class QuestionResult
    {
        public int Id { get; set; }
        public DateTime? DateCreated { get; set; }
        public DateTime? DateModified { get; set; }
        public int QuestionScore { get; set; }
        //navigation properties
        public virtual ApplicationUser User { get; set; }
        public ICollection<CategoryResult> CategoryResult { get; set; }
        public virtual Question Question { get; set; }
        public int QuestionId { get; set; }
    }
}

CategoryResult

using IdentitySample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace STRA.Models
{
    public class CategoryResult
    {
        public int Id { get; set; }
        public int CategoryScore {get;set;}
        //navigation properties
        public virtual QuestionResult QuestionResult { get; set; }
        public int QuestionResultId { get; set; }

    }
}

Any help will be greatly appreciated. HomeController Index

@model IEnumerable<STRA.Models.Question>
@{
    //ViewBag.Question.Title = "Survey";
    Layout = "~/Views/Shared/_QuizLayout.cshtml";

}

<div class="hr hr-18 hr-double dotted"></div>

<div class="widget-box">
    <div class="widget-header widget-header-blue widget-header-flat">
        <h4 class="widget-title lighter">STRA</h4>

        @*<div class="widget-toolbar">
                <label>
                    <small class="green">
                        <b>Validation</b>
                    </small>

                    <input id="skip-validation" type="checkbox" class="ace ace-switch ace-switch-4" />
                    <span class="lbl middle"></span>
                </label>
            </div>*@
    </div>
    @*"Create","Home"*@
    @using (Html.BeginForm("Create", "Home", FormMethod.Post))
    {
        @Html.AntiForgeryToken()

        <div class="widget-body">
            <div class="widget-main">
                <!-- #section:plugins/fuelux.wizard -->
                <div id="fuelux-wizard-container">
                    <div class="col-md-12 center">
                        <div class="easy-pie-chart percentage" data-percent="25" data-color="#2679b5">
                            @*<span class="percent">20</span>%*@
                        </div>
                    </div>
                    <div style="display:none;">

                        <!-- #section:plugins/fuelux.wizard.steps -->
                        <ul class="steps">
                            <li data-step="1" class="active">
                                <span class="step">1</span>
                                <span class="Question.Title">Validation states</span>
                            </li>

                            <li data-step="2">
                                <span class="step">2</span>
                                <span class="Question.Title">Alerts</span>
                            </li>

                            <li data-step="3">
                                <span class="step">3</span>
                                <span class="Question.Title">Payment Info</span>
                            </li>

                            <li data-step="4">
                                <span class="step">4</span>
                                <span class="Question.Title">Other Info</span>
                            </li>
                        </ul>

                        <!-- /section:plugins/fuelux.wizard.steps -->
                    </div>

                    <hr />

                    <!-- #section:plugins/fuelux.wizard.container -->
                    <div class="step-content pos-rel">


                        <div class="step-pane" data-step="1">
                            @{

        foreach (var item in Model.Take(5))
        {

            <div class="col-md-12">
                <h4>@Html.DisplayFor(modelItem => item.Title)</h4>

                <div id="slider-eq">
                    <h5 class="pull-left">Strongly Disagree</h5>
                    <h5 class="pull-right">Strongly Agree</h5>
                    <span id="[email protected](modelItem => item.Id)" class="ui-slider-purple">3</span>
                    <input type="hidden" id="[email protected]" name="[email protected]" value="3" />
                </div>
            </div>

        }
        //Model.Skip(5);
                            }
                        </div>
                        <div class="step-pane" data-step="2">
                            @*<div class="center">
                                    <h3 class="blue lighter">This is step 2</h3>
                                </div>*@
                            @{
        foreach (var item in Model.Skip(5).Take(5))
        {


            <div class="col-md-12">
                <h4>@Html.DisplayFor(modelItem => item.Title)</h4>
                <div id="slider-eq">
                    <h5 class="pull-left">Strongly Disagree</h5>
                    <h5 class="pull-right">Strongly Agree</h5>
                    <span id="[email protected](modelItem => item.Id)" class="ui-slider-purple">3</span>
                    <input type="hidden" id="question_value" name="question_value" value="3" />
                    <input type="hidden" id="questonId" name="questonId" value="@item.Id" />
                           @*<span class="ui-slider-red">55</span>
                    *@></div>
            </div>

        }
                            }
                        </div>

                        <div class="step-pane" data-step="3">
                            @*<div class="center">
                                    <h3 class="blue lighter">This is step 3</h3>
                                </div>*@
                            @{
        foreach (var item in Model.Skip(10).Take(5))
        {


            <div class="col-md-12">
                <h4>@Html.DisplayFor(modelItem => item.Title)</h4>
                <div id="slider-eq">
                    <h5 class="pull-left">Strongly Disagree</h5>
                    <h5 class="pull-right">Strongly Agree</h5>
                    <span id="[email protected](modelItem => item.Id)" class="ui-slider-purple">3</span>
                    <input type="hidden" id="[email protected]" name="[email protected]" value="3" />
                    @*<span class="ui-slider-red">55</span>
                    *@
                </div>
            </div>

        }
                            }
                        </div>

                        <div class="step-pane" data-step="4">
                            @*<div class="center">
                                    <h3 class="blue lighter">This is step 4</h3>
                                </div>*@
                            @{
        foreach (var item in Model.Skip(15).Take(5))
        {


            <div class="col-md-12">
                <h4>@Html.DisplayFor(modelItem => item.Title)</h4>
                <div id="slider-eq">
                    <h5 class="pull-left">Strongly Disagree</h5>
                    <h5 class="pull-right">Strongly Agree</h5>
                    <span id="[email protected](modelItem => item.Id)" class="ui-slider-purple">3</span>
                    <input type="hidden" id="[email protected]" name="[email protected]" value="3" />
                    @*<span class="ui-slider-red">55</span>
                    *@
                </div>
            </div>

        }
                            }
                        </div>
                    </div>

                    <!-- /section:plugins/fuelux.wizard.container -->
                </div>

                <hr />
                <div class="wizard-actions">
                    <!-- #section:plugins/fuelux.wizard.buttons -->
                    <button type="button" id="previous" class="btn btn-prev">
                        <i class="ace-icon fa fa-arrow-left"></i>
                        Prev
                    </button>

                    <button type="button" id="next" class="btn btn-success btn-next" @*data-last="Finish"*@>
                        Next
                        <i class="ace-icon fa fa-arrow-right icon-on-right"></i>
                    </button>
                    <button id="finish" class="btn btn-success" type="submit">
                        Submit
                        <i class="ace-icon fa fa-arrow-right icon-on-right"></i>
                    </button>
                    <!-- /section:plugins/fuelux.wizard.buttons -->
                </div>

                <!-- /section:plugins/fuelux.wizard -->
            </div><!-- /.widget-main -->
        </div>
    <!-- /.widget-body -->
    }
</div>

HomeController

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using IdentitySample.Models;
using STRA.Models;
using System.Collections.Generic;
using System.Diagnostics;
using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

namespace IdentitySample.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        private ApplicationDbContext db = new ApplicationDbContext();
        //public ActionResult Index()
        public ActionResult Index()
        {
            if (User.IsInRole("Admin"))
            {
                return RedirectToAction("Index", "Dashboard");
            }
            if (User.IsInRole("Sales Consultant"))
            {
                return RedirectToAction("Index", "Reports");
            }


            //loads all questions in
            //var questions = db.Questions.Include(s => s.Survey).Include(c => c.Category);

            var questions = db.Questions.Include(c => c.Category);
            return View(questions.ToList());
            //var questionResults = db.QuestionResults.Include(c => c.Question);
            //return View(questionResults.ToList());

            //viewmodel attempt
            //var viewModel = new SurveyViewModels();
            //viewModel.Questions = db.Questions
            //    .Include(i =>)
        }

        [HttpPost]
        public ActionResult Index(FormCollection result)
        {
            List<QuestionResult> info = new List<QuestionResult>();
            QuestionResult newResult = new QuestionResult();
            var appUser = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
            ApplicationUser user = appUser.FindById(User.Identity.GetUserId());
            foreach (var key in result.AllKeys.Where(k => k.Contains("question")).ToArray<string>())
            {
                string[] keys = key.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);

                if (key.Count() > 1)
                {
                    QuestionResult re = new QuestionResult();
                    re.QuestionScore = Convert.ToInt32(result[key]);
                    re.QuestionId = Convert.ToInt32(keys[1]);
                    re.User = user;
                    db.QuestionResults.Add(re);
                }
            }

            db.SaveChanges();

            Debug.WriteLine(result[0]);
            return View();
        }

    }
}

jQuery UI Slider Plugin

$("#slider-eq > span").css({ width: '100%', 'float': 'left', margin: '15px' }).each(function () {
            // read initial values from markup and remove that
            var value = parseInt($(this).text(), 10);
            $(this).empty().slider({
                value: value,
                min: 1,
                max: 5,
                range: "min",
                animate: true,
                change: function (event, ui) {
                    //alert(ui.value);
                    $(this).next("[id^=question_]").val(ui.value);
                    //$(this > ).slider("values", $this.data("index"), $this.val());
                }

            });
        });
6
  • So should I maybe use a viewmodel like this public class SurveyViewModels { public List<Question> Questions { get; set; } public List<CategoryResult> CategoryResult { get; set; } public List<QuestionResult> QuestionResults { get; set; } public List<Category> Category { get; set; } //public List<QuestionFeedback> QuestionFeedbacks { get; set; } } Commented Jun 3, 2015 at 8:15
  • I understand but there is not @Html helper for Range Values, so I stuck to normal html range inputs, I need to have each Question related to the range input, I am not too sure how I would create this ViewModel to be honest... Thanks for your help Commented Jun 3, 2015 at 8:25
  • Hey mate, to be honest I am struggling with it, is there anyway you can provide a bit of assistance in terms of how i would structure my ViewModel? Or if you can point me in the right direction it would be much appreciated... thanks Commented Jun 3, 2015 at 8:34
  • Yes that's exactly what I need I need to do! Yes, then it must retain it's relationship with a Category, pass it onto CategoryResults as 4 accumulated scores, mate please, if you can provide a solution to this, I can offer a payment of some sorts. I see you are in Adelaide, I am in Sydney. Please email message me on my account and I will drop my details or even send you my solution. Thanks again mate this thing is really driving me crazy Commented Jun 3, 2015 at 8:42
  • Ok I will post my scripts as well, thanks so much mate I really appreciate it. You're a saint Commented Jun 3, 2015 at 8:48

2 Answers 2

0

I would in your RazorTemplate add the question category as a prefix to the question_id or question_name which is what comes through via the FormCollection

<input type="hidden" id="@(item.category_id)[email protected]" name="@(item.category_id)[email protected]" value="3" />

Then in your controller action, just pull out the category_id from the start of the name, so you know what category you are currently iterating through.

Sign up to request clarification or add additional context in comments.

Comments

0

Your view code is creating form controls which have no relationship to your models. Instead create view models representing what you need to display/edit in the view, use strongly typed helpers to give you 2-way model binding and post back your view model.

View models

public class SurveyVM
{
  public List<CategoryVM> Categories { get; set; }
  // add any other properties of Survey you need to display/edit (e.g. ID, Title etc)
}

public class CategoryVM
{
  public List<QuestionVM> Questions { get; set; }
  // add any other properties of Category you need to display/edit (e.g. ID, Title etc)
}

public class QuestionVM
{
  public int Id { get; set; }
  public string Title { get; set; }
  public int Score { get; set; }
  // Do not include properties such as DateCreated, User etc
}

Controller

public ActionResult Index()
{
  SurveyVM model = new SurveyVM();
  // populate the categories and for each category, populate the associated questions
  return View(model);
}

[HttpPost]
public ActionResult Index(SurveyVM model)
{
  // loop through each Category, and foreach category loop through each Question to build your `List<QuestionResult>`
}

View

@model yourAssembly.SurveyVM
@using (Html.BeginForm())
{
  // add elements for properties of SurveyVM (ID, Title etc)
  for(int i = 0; i < Model.Categories.Count; i++)
  {
    <div class="category">
      // add elements for properties of each CategoryVM (ID, Title etc)
      @for (int j = 0; j < Model.Categories[i].Questions.Count; j++)
      {
        <div class="question">
          @Html.HiddenFor(m => m.Categories[i].Questions[j].Id)
          @Html.DisplayFor(m => m.Categories[i].Questions[j].Title)
          @Html.TextBoxFor(m => m.Categories[i].Questions[j].Score)
        </div>
      }
    </div>
  }
  <input type="submit" .../>
}

16 Comments

First part of answer added. For the moment forget the scripts. Need to make sure you understand how model binding works first, and in any case there are problems with your scripts - you have duplicate id attributes ("slider-eq") which is invalid html and $("#slider-eq > span") will only ever select the first one. I'll update later with how you can correct this and simplify other aspects of your code. Also suggest you just start by hard coding some CategoryVM and QuestionVM objects in the SurveyVM for testing.
Thanks so much mate I really appreciate it. I will test it right now
hey mate, I am using your approach, but I am receiving a null exception error in the Index view, I have also tried looping through through the post action as below [HttpPost] public ActionResult IndexSurveyViewModel(SurveyViewModel model) { // loop through each Category, and foreach category loop through each Question to build your List<QuestionResult> foreach (var category in model.Categories) { foreach (var question in category.Questions) { } } }
Where are you getting the NullReferenceException? I notice in your POST method that you just use return View(); which may generate an exception (unless you have added hidden inputs for all properties). Is the model correctly populated when you post?
I am disabling the post method for now, as I am not returning anything yet. I am getting the NullExceptionError on Http get, so nothing is really being populated into my view
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.