locked
Need help on required validation on rich text box based off of what is selected in dropdown list. RRS feed

  • 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">&times;</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