问题
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="q_@Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_@item.Id" name="question_@item.Id" 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="q_@Html.DisplayFor(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="q_@Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_@item.Id" name="question_@item.Id" 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="q_@Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_@item.Id" name="question_@item.Id" 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());
}
});
});
回答1:
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)_question_@item.Id" name="@(item.category_id)_question_@item.Id" 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.
回答2:
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" .../>
}
来源:https://stackoverflow.com/questions/30610141/mvc-5-asp-net-entity-framework-collect-form-data-through-range-input