Answered by:
Need help on required validation on rich text box based off of what is selected in dropdown list.

Question
-
User-501297529 posted
I have a view that has two options(Support & Discuss) in the drop down list. When going to the view in a browser the dropdown list is the only thing seen. When I select Discuss in the dropdown the rich text area appears on the view below the form, when I select Support there is no rich text area and I should be able to submit the view. I want to create validation for this rich text area but the problem is no matter whether I select Support or Discuss in the dropdown the view will not submit because the view sees the rich text is also required no matter which option I select. I want the view to submit when I select Support and when I Discuss to validate that the rich text area is required when there is no text in that form. How do I code this?
Currently in the action method in my controller below I have a condition in bold/italics but it will never submit the view or show validation no matter which option I choose in the dropdown.
Controller:
VotingTypeOptions
private static IEnumerable<SelectListItem> GetVotingTypeOptions(string votingType) { if (votingType == "Voting") { return new List<SelectListItem> { new SelectListItem("Support", "1"), new SelectListItem("Discuss", "2") }; } if (votingType == "So-Noted") { return new List<SelectListItem> { new SelectListItem("So-Noted", "3"), new SelectListItem("Discuss", "4") }; } return new List<SelectListItem> { new SelectListItem("No options available", ""), }; }
Vote post action:
public async Task<IActionResult> Vote(VoteViewModel voteViewModel, CancellationToken cancellationToken) { if (ModelState.IsValid) try { var voteToAdd = _mapper.Map<VoteViewModel, Vote>(voteViewModel); var packetItem = await _packetService.GetPacketItemAsync(voteViewModel.PacketItemId, true, cancellationToken) .ConfigureAwait(true); var packet = await _packetService.GetPacketAsync(packetItem.PacketId, true, cancellationToken) .ConfigureAwait(true); return await UseResourceAsync(packet, AuthRequirements.Packet, async () => { return await UseResourceAsync(packet, AuthRequirements.Vote, async () => { await _discussionService.CreateEditVoteAsync(voteToAdd, GetUsername(), cancellationToken) .ConfigureAwait(true); voteViewModel.AvailableVotingOptions = GetVotingTypeOptions(voteViewModel.VotingType); voteViewModel.PacketItemDetails = _mapper.Map<PacketItem, PacketItemDetailsViewModel>(packetItem); // Send Email to all concerned people when a vote is cast var fullName = await _userService.FindNameByUserNameAsync(GetUsername(), cancellationToken) .ConfigureAwait(true); var user = await _userManager.FindByNameAsync(GetUsername()) .ConfigureAwait(true); SelectListItem first = null; foreach (var v in voteViewModel.AvailableVotingOptions) { if (v.Value == voteViewModel.VotingOptionId) { first = v; break; } } if (first != null) { var voteOption = first.Text; var packetItemTitle = voteViewModel.PacketItemId != 0 ? voteViewModel.PacketItemDetails.Title : string.Empty; if (voteOption.ToLower(new CultureInfo("en-US")) == "discuss") { var discussion = new PacketDiscussion { PacketId = packetItem.PacketId, PacketItemId = packetItem.PacketItemId, Post = voteViewModel.Comments, Title = $"Discuss Vote: {packetItem.Title}" }; return await UseResourceAsync(packet, AuthRequirements.Discussion, async () => { await _discussionService.CreateEditDiscussionAsync(discussion, GetUsername(), fullName, false, cancellationToken) .ConfigureAwait(true); // Send email to all the voters and non voters. Non voters wont get voting list await SendVoteEmailToDistributionListAsync( packetItemTitle, discussion.DiscussionId, fullName, packet.MeetingDateTime, packet.PacketId, packet.CommitteeType, cancellationToken) .ConfigureAwait(true); voteViewModel.VoteId = (await _discussionService.FindVoteOnThisPacketItemByUserAsync(packetItem.PacketItemId, user.Id, cancellationToken) .ConfigureAwait(true)).VoteId; return View("Vote", voteViewModel); }).ConfigureAwait(true); } } voteViewModel.VoteId = (await _discussionService.FindVoteOnThisPacketItemByUserAsync(packetItem.PacketItemId, user.Id, cancellationToken) .ConfigureAwait(true)).VoteId; TempData.Put(key: TempDataKey.Vote.AddMessage, StatusMessageModel.Create(UserStringsService.VoteAddedSuccessfully, false)); return View("Vote", voteViewModel); }).ConfigureAwait(true); }).ConfigureAwait(true); } catch (Exception ex) { Logger.LogError(ex, "Error in registering the vote for packet item: " + $"{voteViewModel.PacketItemId}"); } return View("Vote", voteViewModel); }
Here is the view code:
Full View
@{ ViewData["Title"] = "Cast Vote"; Layout = "~/Views/Shared/_Layout.cshtml"; var statusMessage = TempData.Get<StatusMessageModel>(TempDataKey.Vote.AddMessage); var statusMessage2 = TempData.Get<StatusMessageModel>(TempDataKey.Vote.DeleteMessage); } <br/> <h2 class="text-info">@ViewData["Title"]</h2> <hr /> <div class="form-group col-md-8"> <input id="packet-item-id" asp-for="@Model.PacketItemId" type="hidden" /> <input id="voting-type" asp-for="@Model.VotingType" type="hidden" /> </div> <div class="row"> <div class="col-lg-8 col-md-12 col-sm-12"> <partial name="_ClientStatusMessage" /> <partial name="_StatusMessage" for="@statusMessage" /> <partial name="_StatusMessage" for="@statusMessage2" /> <div id="add-edit-vote"> <partial name="_Vote" model="@Model" /> </div> </div> </div>
Partial View
<div>
<input id="voting-id" asp-for="@Model.VoteId" type="hidden" /> <form method="post" id="form-vote"> <div asp-validation-summary="All" id="validation-error" class="text-danger custom-validation-summary"></div> <div class="card"> <div class="card-body"> @{ if (@Model.PacketItemDetails != null) { if (@Model.PacketItemDetails.PacketItemFileId != null && @Model.PacketItemDetails.PacketItemFileId != 0) { <a asp-action="DownloadFile" class="orange" target="_blank" asp-controller="Asset" asp-route-id="@Model.PacketItemDetails.PacketItemFileId "> @Model.PacketItemDetails.Title </a> } else { <div class="forum-orange">@Model.PacketItemDetails.Title</div> } } } <p id="vote-status" class="card-text forum-blue"> @{if (@Model.VoteId != 0) { <text> <br/>You have already voted on this item. <br/>Change by clicking Re-cast Vote or delete vote by clicking Delete Vote </text> } else { <text><br/>You have not voted on this item yet. Vote by selecting an option and clicking Vote.</text> } } </p> @{ if (Model.AvailableVotingOptions != null) { @Html.DropDownListFor(m => m.VotingOptionId, // 1. Store selected value in Model.VotingOptionId // when page is rendered after postback, // take selected value from Model.VotingOptionId. // 2. Take list of values from Model.AvailableVotingOptions Model.AvailableVotingOptions, // 3. Text for the first 'default' option "- Please select a vote -", //4. A class name to assign to <select> tag new { @class = "form-control", @id = "voting-options" }) } } ---Rich Text Area---- <div id="div-discuss-content" style="display: none"> <br/> <div class="control-label">Discuss Content</div> <textarea id="discuss-content" class="discuss-content" asp-for="Comments"></textarea> </div> </div> <div class="card-footer"> <div class="row"> <div class="col-sm-12 col-md-3 col-lg-3"> <button type="submit" class="btn btn-success btn-sm col-sm-12" id="vote-button" data-action="submit"> <i class="fas fa-vote-yea fa-fw"></i> @if (@Model.VoteId != 0) { <text>Re-Cast Vote</text> } else { <text>Vote</text> } </button> </div> <div class="col-sm-12 col-md-3 col-lg-3"> <a data-toggle="modal" id="delete-vote-button" data-id="@Model.VoteId" href="#delete-vote-modal" class="btn btn-danger btn-sm delete-vote col-sm-12"> <i class="fa fa-trash fa-fw" title="Delete" style="color: white"></i>Delete Vote </a> </div> <div class="col-sm-12 col-md-3 col-lg-3"> <button type="button" class="btn btn-forum btn-sm col-sm-12" id="back-to-packet"> <i class="fas fa-arrow-alt-circle-left fa-fw"></i> Back To Packet </button> </div> </div> </div> </div> </form> <!-- start: Delete vote modal --> <!-- Modal --> <div class="modal fade" id="delete-vote-modal" tabindex="-1" role="dialog" data-backdrop="static"> <form method="post" id="voteId" asp-controller="Discussion" asp-action="DeleteVote"> <input id="vote-id" asp-for="@Model.VoteId" type="hidden" /> <input id="packet-item-id" asp-for="@Model.PacketItemId" type="hidden" /> <input id="voting-type" asp-for="@Model.VotingType" type="hidden" /> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Delete Vote</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <input type="hidden" name="voteId" id="voteId" value=""/> Do you want to delete this vote ? <div style="text-align: center; display: none" id="loaderDiv"> <img src="~/images/loading.gif" width="150"/> </div> </div> <div class="modal-footer"> <a href="#" class="btn btn-default" data-dismiss="modal">Cancel</a> <button type="submit" class="btn btn-success">Confirm</button> </div> </div> </div> </form> </div>
</div>Monday, December 7, 2020 9:41 PM
Answers
-
User711641945 posted
Hi bootzilla,
Your code is a bit complex,you need provide a minimum code to reproduce your issue.What is your rich text?Did you use any plugin?
Here is a simple demo below,when you choose Discuss,the text area will display and you must enter value.When you choose Support,the text area will not display and could pass the validation successfully:
Model:
public class VoteViewModel { [RequieredIf("VoteOption")] public string Area { get; set; } public string VoteOption { get; set; } }
View(Pricacy.cshtml):
@model VoteViewModel <form asp-action="Vote"> <select asp-for="VoteOption" asp-items="ViewBag.select"></select> <div id="div_Area" class="form-group" style="display:none"> <label asp-for="Area" class="control-label"></label> <input asp-for="Area" class="form-control" /> <span asp-validation-for="Area" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} <script> $(function () { var data = $('select').val(); if (data == "Discuss") { $("#div_Area").removeAttr("style") } }); $('select').on('change', function () { var data = this.value; if (data == "Discuss") { $("#div_Area").removeAttr("style") } else{ $("#div_Area").css("display","none") } }); </script> }
Validation:
public class RequieredIfAttribute : ValidationAttribute { private readonly string _otherProperty; public RequieredIfAttribute(string otherProperty) { _otherProperty = otherProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { string data = (string)value; var selectedType = (string)validationContext.ObjectType.GetProperty(_otherProperty).GetValue(validationContext.ObjectInstance, null); if (string.IsNullOrEmpty(data) && selectedType == "Discuss") { return new ValidationResult("Area is requiered."); } return ValidationResult.Success; } }
Controller:
public IActionResult Privacy() { ViewBag.select = new List<SelectListItem>() { new SelectListItem() { Value = "Support", Text = "Support" }, new SelectListItem() { Value = "Discuss", Text = "Discuss" } }; return View(); } [HttpPost] public async Task<IActionResult> Vote(VoteViewModel voteViewModel) { if(ModelState.IsValid) { return View("Index"); } //add the following code to keep the the select list data when rerendering the page ViewBag.select = new List<SelectListItem>() { new SelectListItem() { Value = "Support", Text = "Support" }, new SelectListItem() { Value = "Discuss", Text = "Discuss" } }; return View("Privacy"); }
Result:
Reference:
https://stackoverflow.com/a/65136958/11398810
Best Regards,
Rena
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Tuesday, December 8, 2020 9:32 AM
All replies
-
User711641945 posted
Hi bootzilla,
Your code is a bit complex,you need provide a minimum code to reproduce your issue.What is your rich text?Did you use any plugin?
Here is a simple demo below,when you choose Discuss,the text area will display and you must enter value.When you choose Support,the text area will not display and could pass the validation successfully:
Model:
public class VoteViewModel { [RequieredIf("VoteOption")] public string Area { get; set; } public string VoteOption { get; set; } }
View(Pricacy.cshtml):
@model VoteViewModel <form asp-action="Vote"> <select asp-for="VoteOption" asp-items="ViewBag.select"></select> <div id="div_Area" class="form-group" style="display:none"> <label asp-for="Area" class="control-label"></label> <input asp-for="Area" class="form-control" /> <span asp-validation-for="Area" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} <script> $(function () { var data = $('select').val(); if (data == "Discuss") { $("#div_Area").removeAttr("style") } }); $('select').on('change', function () { var data = this.value; if (data == "Discuss") { $("#div_Area").removeAttr("style") } else{ $("#div_Area").css("display","none") } }); </script> }
Validation:
public class RequieredIfAttribute : ValidationAttribute { private readonly string _otherProperty; public RequieredIfAttribute(string otherProperty) { _otherProperty = otherProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { string data = (string)value; var selectedType = (string)validationContext.ObjectType.GetProperty(_otherProperty).GetValue(validationContext.ObjectInstance, null); if (string.IsNullOrEmpty(data) && selectedType == "Discuss") { return new ValidationResult("Area is requiered."); } return ValidationResult.Success; } }
Controller:
public IActionResult Privacy() { ViewBag.select = new List<SelectListItem>() { new SelectListItem() { Value = "Support", Text = "Support" }, new SelectListItem() { Value = "Discuss", Text = "Discuss" } }; return View(); } [HttpPost] public async Task<IActionResult> Vote(VoteViewModel voteViewModel) { if(ModelState.IsValid) { return View("Index"); } //add the following code to keep the the select list data when rerendering the page ViewBag.select = new List<SelectListItem>() { new SelectListItem() { Value = "Support", Text = "Support" }, new SelectListItem() { Value = "Discuss", Text = "Discuss" } }; return View("Privacy"); }
Result:
Reference:
https://stackoverflow.com/a/65136958/11398810
Best Regards,
Rena
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Tuesday, December 8, 2020 9:32 AM -
User-501297529 posted
Updated code in original post.
Tuesday, January 19, 2021 9:25 PM