I created a survey that contains questions with answers. I am editing it and in this view, I am looping each section with its questions using the custom tag helper and I am wondering how I can get information from all that once I submit a post request in the forms. You can use asp-for attribute for each input but in this case, is there a way I can get information from this? I am editing its value and saving it to the database.
The survey view:
<form asp-controller="Response" asp-action="Edit" method="post">
@foreach (Section section in Model.Survey.Metadata.Sections.OrderBy(e => e.Position))
{
<div class="card" id="a@(section.Id.Replace("-", ""))">
<div class="card-body">
<h1>@(section.Title)</h1>
@if (!string.IsNullOrEmpty(section.Description))
{
<div>
@Html.Raw(section.Description)
</div>
}
<hr />
@foreach (QuestionMetadata question in Model.Survey.Questions.Where(e => e.SectionId == section.Id).OrderBy(e => e.Position))
{
<script>
@(ViewData["id"])SetValue[@Html.Raw($"\"a{question.Id.ToString().Replace("-", "").Split(":")[1]}\"")] = function (value, modified = true) {
$("#@($"{ViewData["id"]}-{question.Id.ToString().Replace("-", "").Split(":")[1]}-value")").val(JSON.stringify(
{
Value: value,
QuestionId: "@question.Id",
Modified: modified
}
));
};
@(ViewData["id"])GetValue[@Html.Raw($"\"a{question.Id.ToString().Replace("-", "").Split(":")[1]}\"")] = function () {
return JSON.parse(
$("#@($"{ViewData["id"]}-{question.Id.ToString().Replace("-", "").Split(":")[1]}-value")").val())
.Value;
};
</script>
<question survey="@Model.Survey.Metadata" answers="@Model.Survey.Metadata.Answers.ToArray()" survey-id="@ViewData["id"]" question=@question answer="@Model.Survey.Metadata.Answers.First(e => e.QuestionId == question.Id)" site-id="@Model.Survey.Metadata.SiteId" />
<hr />
}
</div>
</div>
}
<div class="card">
<div class="card-body">
<button type="submit" asp-route-SurveyId="@Model.Survey.Metadata.Id" class=" @($"{ViewData["id"]}-button-{Model.Survey.Metadata.Id.Replace(":", "")}-survey-js")
button-anchor">
Submit
</button>
</div>
</div>
</form>
The question tag helper view:
using ApplicationCore.Entities;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Threading.Tasks;
using Web.Models;
namespace Web.TagHelpers
{
// You may need to install the Microsoft.AspNetCore.Razor.Runtime package into your project
[HtmlTargetElement("question")]
public class QuestionTagHelper : BaseTagHelper
{
[HtmlAttributeName("asp-for")]
public ModelExpression AspFor { get; set; }
public QuestionMetadata Question { get; set; }
public Answer Answer { get; set; }
public string SurveyId { get; set; } = Guid.NewGuid().ToString();
public string SiteId { get; set; }
public SurveyMetadata Survey { get; set; }
public Answer[] Answers { get; set; }
public QuestionTagHelper(ICompositeViewEngine viewEngine,
IViewBufferScope viewBufferScope) : base(viewEngine, viewBufferScope)
{
}
public override async Task RunAsync(TagHelperContext context, TagHelperOutput output)
{
string name = this.AspFor.Name;
if (!string.IsNullOrEmpty(name))
{
output.Attributes.Add("name", name);
}
ViewContext.ViewData["survey-id"] = SurveyId;
Model = new QuestionTagHelperModel()
{
Question = Question,
Answer = Answer,
Required = Question.IsRequired
.Invoke(new()
{
{ "Survey", Survey },
{ "Answers", Answers }
}),
SiteId = SiteId,
Year = Survey.Year
};
output.TagMode = TagMode.StartTagAndEndTag;
}
}
}
Action method:
[HttpPost]
[Authorize(Roles = "Administrator")]
public async Task<IActionResult> Edit(Edit.Command command)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Index");
}
Edit.CommandResponse response = await _mediator.Send(command);
if (response.NotFound)
{
return RedirectToAction("Index");
}
else
{
return View(response);
}
}
The model:
public class Command : IRequest<CommandResponse>
{
[Required]
[HiddenInput]
public string Id { get; set; }
public ApplicationCore.Entities.Survey Survey { get; set; }
public List<QuestionTagHelperModel> Questions { get; set; }
public string SurveyId { get; set; }
}
I tried adding ModelExpression For but it still doesn't work.
I would try creating a model that represents the structure of your sections, questions, and answers, and then using the asp-for attribute to bind the input fields to the model properties. when the form is then submitted, the data will be bound to the model and can be easily accessed in your action method.