Прежде всего, я новичок в этом. Имею некоторый опыт работы с asp.net, но я уже 8 лет назад, и с тех пор многое изменилось.
Я уверен, что моя проблема довольно проста для опытного разработчика, у меня просто нет опыта и знаний, чтобы ее исправить.
Я создаю модель представления, которая передается в режим бритвы. Это представление генерирует динамическую форму, и все это работает хорошо. В основном он задает несколько вопросов в группах, и мне нужно убедиться, что пользователь выбрал ответ на каждый вопрос перед отправкой.
Форма теста выглядит следующим образом: Форма теста
Каждый вопрос создается в виде списка переключателей, и я должен убедиться, что на все вопросы есть ответ, прежде чем его можно будет отправить.
Текущее представление, которое содержит функцию javascript, которая работает некоторым образом ... она вообще запрещает мне отправлять сообщения ... поэтому я смотрю на что-то, что не совсем правильно, но в большинстве случаев верно. Так что, думаю, мне нужна небольшая помощь, чтобы исправить эту часть или изменить способ, которым она делается, на что-то лучшее?
@using RefereeOnline.Models.FormsViewModels
@model RenderFormViewModel
@{
ViewData["Title"] = "Evaluate";
}
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script>
function ValidateForm() {
var isFormValid = true;
$("#evaluateform input,select").each(function () {
var FieldId = "span_" + $(this).attr("id");
if ($.trim($(this).val()).length == 0 || $.trim($(this).val()) == 0) {
$(this).addClass("highlight");
//Show required message along with the field
if ($("#" + FieldId).length == 0) {
$("<span class='error' id='" + FieldId + "'>Required</span>").insertAfter(this);
}
//If you fill and again make the field empty in that case again show the message
if ($("#" + FieldId).css('display') == 'none') {
$("#" + FieldId).fadeIn(500);
}
//$(this).focus();
isFormValid = false;
}
else {
$(this).removeClass("highlight");
if ($("#" + FieldId).length > 0) {
// Hide the message with the fade out effect
$("#" + FieldId).fadeOut(1000);
}
}
});
return isFormValid;
}
</script>
<h2>Evaluate (@Model.FormTitle @Model.FormVersion)</h2>
@using (Html.BeginForm("Evaluate", "Forms", FormMethod.Post, new { id = "evaluateform" }))
{
<div>
<hr />
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>@Model.PersonName</dd>
<dt>Match</dt>
<dd>@Model.ActivityInfo</dd>
<dt>Level</dt>
<dd>@Model.LevelName</dd>
</dl>
<hr />
@for (int g = 0; g < Model.Groups.Count; g++)
{
<table class="table">
@Html.Hidden("Model.Groups[" + @g + "].GroupId", Model.Groups[g].GroupId)
@if (Model.Groups[g].Answers.Any())
{
<tr>
<td></td>
@foreach (var answer in Model.Groups[g].Answers)
{
<td>@answer.Text</td>
}
@if (Model.Groups[g].Questions.Any(x => x.AllowComment))
{
<td>Comment</td>
}
</tr>
}
@for (int i = 0; i < Model.Groups[g].Questions.Count; i++)
{
<tr>
<td>@Model.Groups[g].Questions[i].Text</td>
@if (Model.Groups[g].Answers.Any() && !Model.Groups[g].Questions[i].Answers.Any())
{
foreach (var answer in Model.Groups[g].Answers)
{
<td>
@Html.RadioButton("Model.Groups[" + g + "].Questions[" + i + "].SelectedAnswer", answer.Id)
@Html.Label(answer.Value.ToString(), answer.Value.ToString())
@Html.Hidden("Model.Groups[" + g + "].Questions[" + i + "].FieldId", Model.Groups[g].Questions[i].FieldId)
</td>
}
}
else if (Model.Groups[g].Questions[i].Answers.Any()) //single question with answers
{
foreach (RenderAnswer answer in Model.Groups[g].Questions[i].Answers)
{
<td>
@Html.RadioButton("Model.Groups[" + g + "].Questions[" + i + "].SelectedAnswer", answer.Id)
@Html.Label(answer.Value.ToString(), answer.Text)
@Html.Hidden("Model.Groups[" + g + "].Questions[" + i + "].FieldId", Model.Groups[g].Questions[i].FieldId)
</td>
}
}
else //single question with textbox
{
<td>@Html.TextBox("Model.Groups[" + g + "].Questions[" + i + "].AnswerValue", Model.Groups[g].Questions[i].AnswerValue)</td>
}
@if (Model.Groups[g].Questions.Any(x => x.AllowComment))
{
<td>
@if (Model.Groups[g].Questions[i].AllowComment)
{
@Html.TextArea("Model.Groups[" + g + "].Questions[" + i + "].Comment", Model.Groups[g].Questions[i].Comment, 2, 40, null)
}
</td>
}
</tr>
}
</table>
}
</div>
@Html.Hidden("Model.CustomerId", Model.CustomerId)
@Html.Hidden("Model.FormId", Model.FormId)
@Html.Hidden("Model.UserId", Model.UserId)
@Html.Hidden("Model.ActivityId", Model.ActivityId)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" onclick="return ValidateForm();" /> |
@Html.ActionLink("Back", "PlannedEvaluations", "Person", new { userid = Model.UserId })
</div>
</div>
}
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
<!--onclick="return ValidateForm();" -->
Моя модель просмотра:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace RefereeOnline.Models.FormsViewModels
{
public class RenderFormViewModel
{
public Guid CustomerId { get; set; }
public Guid FormId { get; set; }
public string UserId { get; set; }
public string FormTitle { get; set; }
public string FormVersion { get; set; }
public Guid ActivityId { get; set; }
public string PersonName { get; set; }
public string ActivityInfo { get; set; }
public string LevelName { get; set; }
public List<RenderGroup> Groups { get; set; } = new List<RenderGroup>();
}
public class RenderGroup
{
public string GroupId { get; set; }
public List<RenderQuestion> Questions { get; set; } = new List<RenderQuestion>();
/// <summary>
/// Contains a list of possible answers to limit to
/// If empty, no limited answers
/// </summary>
public List<RenderAnswer> Answers { get; set; } = new List<RenderAnswer>();
}
public class RenderQuestion
{
public Guid FieldId { get; set; }
public string Text { get; set; }
/// <summary>
/// Specific answers for this field
/// Used if in a group, but answers not re-used
/// </summary>
public List<RenderAnswer> Answers { get; set; } = new List<RenderAnswer>();
public string AnswerValue { get; set; }
public Guid SelectedAnswer { get; set; }
public bool AllowComment { get; set; }
public string Comment { get; set; }
}
public class RenderAnswer
{
public Guid Id { get; set; }
public string Text { get; set; }
public int Value { get; set; }
}
}
Мой контроллер (имеет контекст ядра EF), удалил все ненужные методы:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite.Internal.UrlActions;
using Microsoft.EntityFrameworkCore;
using RefereeDb.Entities;
using RefereeOnline.Data;
using RefereeOnline.Data.Entities;
using RefereeOnline.Models.FormsViewModels;
using Activity = RefereeOnline.Data.Entities.Activity;
namespace RefereeOnline.Controllers
{
[Authorize]
[Route("[controller]/[action]")]
public class FormsController : Controller
{
private readonly RefereeContext _context;
public FormsController(
RefereeContext context)
{
_context = context;
}
public IActionResult Evaluate(Guid eventid, Guid activityid)
{
var eventData = _context.Events.Find(eventid);
var customer = _context.Customers.Find(eventData.CustomerId);
var activityData = _context.Activities.Include(m => m.MetaData).ThenInclude(f => f.Field)
.ThenInclude(mf => mf.MetaField).Include(l => l.Level).ThenInclude(t => t.Type)
.ThenInclude(r => r.CustomerReferences).First(x => x.Id == activityid);
EvaluationForm form = null;
try
{
form = _context.EvaluationForms.Include(f => f.Fields).ThenInclude(a => a.Answers)
.First(x => x.Id == activityData.Level.Type.CustomerReferences
.First(c => c.CustomerId == customer.Id &&
c.LicenseTypeId == activityData.Level.LicenseTypeId).EvaluationFormId);
}
catch (Exception ex)
{
return RedirectToAction("ShowMessage", "Site",
new
{
message = $"Evaluation forms not configured correctly for {activityData.Level.Name}",
returnurl = HttpUtility.HtmlEncode(Url.Action("Index", "Home"))
});
}
var model = BuildViewModel(form);
model.ActivityId = activityData.Id;
var user = _context.Users.First(x => x.Id == activityData.PersonId);
model.PersonName = user.FullName;
model.LevelName = activityData.Level.Name;
model.ActivityInfo =
$"{activityData.Date.ToShortDateString()} {activityData.Date.ToShortTimeString()} {activityData.Place}";
foreach (CustomerMetaFieldData data in activityData.MetaData.OrderBy(o => o.Field.MetaField.Order))
model.ActivityInfo += $" {data.FieldValue}";
return View(model);
}
[HttpPost]
public IActionResult Evaluate(RenderFormViewModel model)
{
var activity = _context.Activities.Include(l => l.Level).ThenInclude(r => r.Rules).Include(p => p.Person)
.ThenInclude(l => l.Licenses).ThenInclude(t => t.Type).First(x => x.Id == model.ActivityId);
_context.Entry(activity.Person).Collection(x => x.Batches).Load();
//batch id is assigned in post processing
Evaluation evaluation = new Evaluation { ActivityId = activity.Id, EvaluationFormId = model.FormId};
activity.EvaluationData = evaluation;
var customer = _context.Customers.Include(t => t.AssociatedTypes).ThenInclude(s => s.EvaluationSetup)
.First(x => x.Id == model.CustomerId);
var setups = customer.AssociatedTypes.First(t => t.LicenseTypeId == activity.Level.LicenseTypeId)
.EvaluationSetup.Where(x => x.LicenseLevelId == activity.LicenseLevelId);
_context.SaveChanges();
try
{
//load the form
_context.Entry(activity.EvaluationData).Reference(f => f.EvaluationForm).Load();
_context.Entry(activity.EvaluationData.EvaluationForm).Collection(f => f.Fields).Load();
foreach (EvaluationFormField field in activity.EvaluationData.EvaluationForm.Fields)
_context.Entry(field).Collection(a => a.Answers).Load();
Dictionary<string, int> points = new Dictionary<string, int>();
foreach (RenderGroup renderGroup in model.Groups.Where(x => !string.IsNullOrEmpty(x.GroupId)))
{
var groupSetup = setups.FirstOrDefault(x => x.Group == renderGroup.GroupId);
if (renderGroup.GroupId != null)
points.Add(renderGroup.GroupId, 0);
foreach (RenderQuestion question in renderGroup.Questions)
{
activity.EvaluationData.Data.Add(new EvaluationData
{
FieldId = question.FieldId,
AnswerId = question.SelectedAnswer,
EvaluationId = activity.EvaluationData.Id,
Comment = question.Comment
});
if (renderGroup.GroupId != null)
{
var currentField =
activity.EvaluationData.EvaluationForm.Fields.First(f => f.Id == question.FieldId);
FieldAnswer currentAnswer = null;
if (currentField.SameAnswersForAll)
{
var field = activity.EvaluationData.EvaluationForm.Fields.First(x =>
x.Answers.Any() && x.Group == renderGroup.GroupId);
var answers = field.Answers;
currentAnswer = answers.FirstOrDefault(a => a.Id == question.SelectedAnswer);
}
else
{
currentAnswer = currentField.Answers.First(a => a.Id == question.SelectedAnswer);
}
points[renderGroup.GroupId] += currentAnswer.Points;
}
}
if (renderGroup.GroupId != null)
{
var fields =
activity.EvaluationData.EvaluationForm.Fields.Where(x => x.Group == renderGroup.GroupId);
int max = 0;
if (fields.Any(x => x.SameAnswersForAll))
{
max = fields.First(x => x.Answers.Any()).Answers.Max(m => m.Points) * fields.Count();
}
else
{
max = fields.Sum(x => x.Answers.Max(a => a.Points));
}
EvaluationPointSums newPoints =
new EvaluationPointSums
{
GroupId = renderGroup.GroupId,
EvaluationId = evaluation.Id,
Points = points[renderGroup.GroupId],
Threshold = groupSetup?.PassThreshold ?? 0,
Maximum = max
};
evaluation.Points.Add(newPoints);
}
}
_context.Audit.Add(new Audit(User.Identity.Name, evaluation.Id, "Evaluation added"));
_context.SaveChanges();
}
catch (Exception)
{
//reverting the evaluation
_context.Evaluations.Remove(evaluation);
_context.SaveChanges();
//todo: go to message
}
//post processing the evaluation... should new license be created? or expired..
PostProcessEvaluation(activity, evaluation);
return RedirectToAction("EvaluationResult", new { evaluationid = evaluation.Id });
}
public IActionResult EvaluationDetails(Guid activityid, Guid evaluationid, bool score, bool data, string userid)
{
//getting event, activity, metadata, form etc...
var activity = _context.Activities.Include(e => e.EvaluationData).ThenInclude(f => f.EvaluationForm)
.ThenInclude(ff => ff.Fields).ThenInclude(fc => fc.Answers).Include(m => m.MetaData)
.ThenInclude(fd => fd.Field).ThenInclude(d => d.MetaField).Include(e => e.Event).Include(l => l.Level)
.First(x => x.Id == activityid);
_context.Entry(activity.EvaluationData).Collection(x => x.Data).Load();
_context.Entry(activity.EvaluationData).Collection(x => x.Points).Load();
foreach (var evaluationData in activity.EvaluationData.Data)
_context.Entry(evaluationData).Reference(x => x.Answer).Load();
DisplayEvaluationViewModel model = new DisplayEvaluationViewModel { UserId = userid };
model.Activity = activity;
model.RenderModel = BuildViewModel(activity.EvaluationData.EvaluationForm);
return View(model);
}
private void PostProcessEvaluation(Activity activity, Evaluation evaluation)
{
EvaluationRule rule = activity.Person.HasLicense(activity.LicenseLevelId)
? activity.Level.Rules.FirstOrDefault(x => x.Scope == LicenseScope.Licensed)
: activity.Level.Rules.FirstOrDefault(x => x.Scope == LicenseScope.Trainee);
if (rule != null) //if no rule, nothing happens
{
var batch = activity.Person.Batches.FirstOrDefault(x => x.LevelId == activity.LicenseLevelId);
if (batch == null)
{
//creating new batch, marking evaluation with it
batch = new EvaluationIdentityBatch { CurrentBatch = Guid.NewGuid(), LevelId = activity.LicenseLevelId, PersonId = activity.PersonId };
evaluation.BatchId = batch.Id;
activity.Person.Batches.Add(batch);
_context.SaveChanges();
}
//get all evaluations belonging to this batch
var evals = _context.Evaluations.Where(x => x.BatchId == batch.CurrentBatch);
if (evals.Count(x => x.IsPassed) == rule.Goal)
{
//target hit, all is good, execute passed action
ExecuteAction(rule.SuccessAction, activity);
}
else if (evals.Count() == rule.Tries)
{
//execute failed action
ExecuteAction(rule.FailAction, activity);
}
else
{
//log that nothing happens....
Trace.TraceError("Rule found, but not triggered");
}
}
}
private void ExecuteAction(EvalAction action, Activity activity)
{
switch (action)
{
case EvalAction.Issue:
License newLicense = new License
{
Assigned = DateTime.Now,
CustomerId = activity.Person.CustomerId,
LicenseLevelId = activity.LicenseLevelId,
LicenseTypeId = activity.Level.LicenseTypeId,
PersonId = activity.Person.Id,
Recorded = DateTime.Now
};
activity.Person.Licenses.Add(newLicense);
_context.Audit.Add(new Audit(User.Identity.Name, newLicense.Id, "Created by rule"));
break;
case EvalAction.Expire:
var license =
activity.Person.CurrentLicenses.First(x => x.LicenseLevelId == activity.LicenseLevelId);
license.LastActivity = DateTime.Now;
license.ForceExpiry = true;
_context.Audit.Add(new Audit(User.Identity.Name, license.Id, "Expired by rule"));
break;
}
var batch = activity.Person.Batches.First(x => x.LevelId == activity.LicenseLevelId);
activity.Person.Batches.Remove(batch);
_context.SaveChanges();
}
public IActionResult EvaluationResult(Guid evaluationid)
{
EvaluationResultViewModel model = new EvaluationResultViewModel();
var evaluation = _context.Evaluations.Include(p => p.Points).Include(a => a.Activity)
.ThenInclude(m => m.MetaData).First(x => x.Id == evaluationid);
_context.Entry(evaluation.Activity).Reference(p => p.Person).Load();
_context.Entry(evaluation.Activity).Reference(l => l.Level).Load();
_context.Entry(evaluation.Activity).Collection(r => r.Relations).Load();
model.Evaluation = evaluation;
return View(model);
}
private RenderFormViewModel BuildViewModel(EvaluationForm form)
{
ApplicationUser user = _context.Users.Include(m => m.AssociationMembers).First(x => x.UserName == User.Identity.Name);
RenderFormViewModel model = new RenderFormViewModel { CustomerId = form.CustomerId, FormId = form.Id, FormVersion = form.FormVersion, FormTitle = form.Name, UserId = user.Id };
foreach (EvaluationFormField field in form.Fields.OrderBy(x => x.SortOrder))
{
if (string.IsNullOrEmpty(field.Group))
{
//normal field
RenderGroup group = new RenderGroup();
RenderQuestion newQuestion = new RenderQuestion { Text = field.Text, FieldId = field.Id };
newQuestion.Answers.AddRange(field.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText, Value = x.Points }));
group.Questions.Add(newQuestion);
model.Groups.Add(group);
}
else
{
//grouped field
RenderGroup group = model.Groups.FirstOrDefault(x => x.GroupId == field.Group);
if (group == null)
{
//group does not exist... create + add answers
group = new RenderGroup { GroupId = field.Group };
if (field.SameAnswersForAll)
{
var answerfield = form.Fields.Where(x => x.Group == field.Group && x.Answers.Any())
.OrderBy(o => o.SortOrder).FirstOrDefault();
if (answerfield != null)
{
//adding general answers
group.Answers.AddRange(answerfield.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText, Value = x.Points }));
}
}
model.Groups.Add(group);
}
//creating the question
RenderQuestion newQuestion = new RenderQuestion { FieldId = field.Id, Text = field.Text, AllowComment = field.AddComment };
//adding specific answers
if (!field.SameAnswersForAll && field.Answers.Any())
newQuestion.Answers.AddRange(field.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText }));
group.Questions.Add(newQuestion);
}
}
return model;
}
#region create
}
}