gpt4 book ai didi

javascript - 在提交 asp.net core 2.0 之前验证表单

转载 作者:行者123 更新时间:2023-11-29 20:54:08 25 4
gpt4 key购买 nike

首先,我是这方面的初学者。有一些使用 asp.net 的经验,但那是 8 年前的事了,从那以后发生了很多变化。

我确信我的问题对于有经验的开发人员来说非常简单,我只是没有经验和知识来解决它。

我生成了一个传递给 Razor View 的 View 模型。这个 View 生成一个动态表单,并且一切正常。它基本上是按组提出一些问题,我需要在提交之前验证用户是否为每个问题选择了答案。

测试表单如下所示:test form

每个问题都创建为单选按钮列表,我需要确保所有问题都有答案,然后才能提交。

当前 View ,其中包含一个以某种方式工作的 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();" -->

我的 View 模型:

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; }
}
}

我的 Controller (有一个 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
}
}

最佳答案

注意 更新了脚本部分

这只是部分答案,没有解决脚本以外的任何缺点。我会采取一些小步骤来重构,但最终我会在您的模型上使用内置验证,但这需要更多的学习/讨论。

这可能是你可以改变以继续前进的东西,下面的片段是过去对我有用的东西,但有很多意见所以看看是否有用或有帮助:

Controller

[Route("VerifyForm")]
public IActionResult VerifyForm()
{
var viewModel = new VerifyModel()
{
Store = "",
DateFrom = DateTime.Now,
};

return View(viewModel);
}


/// <summary>
/// Called by a form post
/// </summary>
[HttpPost("VerifyForm")]
public IActionResult VerifyForm(VerifyModel model)
{
if (!ModelState.IsValid)
{
// finding modelstate validation errors
var errors = ModelState.Values.SelectMany(v => v.Errors);
foreach (var err in errors)
{
_logger.LogError($"Model State err: {err.ErrorMessage}");
}
return View(model);
}

// do something with the model data

// . . .

// return back to the view - or another view - whatever you wish
return View(model);
}

查看

<form asp-action="VerifyForm" asp-controller="Admin" method="post">

<!-- form fields here -->

<!-- this triggers the post, called in .js -->
<input type="submit" id="inputSave" style="display: none" />
</form>

<!-- my visible button bound to in .js -->
<button id="buttonSaveUser" class="btn btn-sm btn-primary" title="Click to save">
Save
</button>

Javascript

首先,查看我对 View 和您对提交功能的使用的评论,更改您的 View ,然后假设您可以修改脚本

其次,将您的脚本移动到我在您的 View 中看到的这一点,脚本不应在顶部运行:

<script>

// initialize the buttons or other ui events
// for those who complain: Yes, there are other ways to do things but this is simple

$(function(){

// I'll assume this is the name of your new button
// bind to the button this way, get rid of onClick in your view

$('#buttonSaveUser').on('click', function ()
{
// this is my call to do some other validation, if not valid just exit
if (ValidateForm() === false) return;

// triggers the submit button which triggers the post
$('#inputSave').click();
});
});


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>
  • 不要使用提交来运行客户端脚本 - 它意味着触发表单 POST - 我会创建一个绑定(bind)客户端的基本按钮
  • 摆脱 onClick='' 并在 javascript 中绑定(bind)

希望这能有所帮助。

关于javascript - 在提交 asp.net core 2.0 之前验证表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50240613/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com