Search code examples
javascriptc#jqueryasp.netcustomvalidator

ASP CustomValidator fails and Modal doesn't clear from screen


I am adding a new field to a form. The form is used to update a status from not approved to approved.The goal is to make sure that if no changes are made but the update button is clicked, an error is displayed and no update is processed. This did work before I added the new field and switched from a RequiredFieldValidator to a CustomValidator.

The Problem

Now, when no changes are made to the drop downs the modal closes but the rest of the window is grayed out and the application seems to hang.

This is a bit over my head a great learning experience.

EDIT:

Error from the console

Doc-Comp-Composition-Templates:348 Uncaught TypeError: $(...).ddlCS is not a function
    at ValidateStatusChange_ClientValidate (Doc-Comp-Composition-Templates:348)
    at eval (eval at CustomValidatorEvaluateIsValid (ScriptResource.axd?d=nv7asgRUU0tRmHNR2D6t1FZw7wze8nmx-kJRmw2XEjbK3oXSAIyhKQNPF6n1kyJ-XavItdyBmyr8jQKkgUwJ4hvE-EOowyd5E-dQMLMfuYhYi3DooAGZ6tCMyoNO-1bI0OD14u047d3MStBJK15cjQ2&t=fffffffff974e48e:450), <anonymous>:1:1)
    at HTMLSpanElement.CustomValidatorEvaluateIsValid [as evaluationfunction] (ScriptResource.axd?d=nv7asgRUU0tRmHNR2D6t1FZw7wze8nmx-kJRmw2XEjbK3oXSAIyhKQNPF6n1kyJ-XavItdyBmyr8jQKkgUwJ4hvE-EOowyd5E-dQMLMfuYhYi3DooAGZ6tCMyoNO-1bI0OD14u047d3MStBJK15cjQ2&t=fffffffff974e48e:450)
    at ValidatorValidate (ScriptResource.axd?d=nv7asgRUU0tRmHNR2D6t1FZw7wze8nmx-kJRmw2XEjbK3oXSAIyhKQNPF6n1kyJ-XavItdyBmyr8jQKkgUwJ4hvE-EOowyd5E-dQMLMfuYhYi3DooAGZ6tCMyoNO-1bI0OD14u047d3MStBJK15cjQ2&t=fffffffff974e48e:200)
    at Page_ClientValidate (ScriptResource.axd?d=nv7asgRUU0tRmHNR2D6t1FZw7wze8nmx-kJRmw2XEjbK3oXSAIyhKQNPF6n1kyJ-XavItdyBmyr8jQKkgUwJ4hvE-EOowyd5E-dQMLMfuYhYi3DooAGZ6tCMyoNO-1bI0OD14u047d3MStBJK15cjQ2&t=fffffffff974e48e:119)
    at Sys$WebForms$PageRequestManager$_doPostBackWithOptions [as _doPostBackWithOptions] (ScriptResource.axd?d=JnUc-DEDOM5KzzVKtsL1tRZpRA_LXrniqfBmVmIZ3cAuPpCW1plWZw2RXdO0zo-BiAzza2U9Udple6pVeaDdyS14EzqQJMs1mhrjSf56Z17-S803UF2Z43EZ-6v-WWTiunEhUO4tmGiISgd0nYLoQNVyt3LQvd2TOLU7l5Fq6n-tE3oJIofGXa6OGTnxPRDQ0&t=fffffffffc18b87d:831)
    at ScriptResource.axd?d=D9drwtSJ4hBA6O8UhT6CQi4RxEM3HXQdD1kANRSxcVDQlciZR3AdFzJCI2OSpEJ8btryaMvtylBgqedQo2VFV1HT2WfhU1dHTVqnIz5ypNeiBiXQQMaUQfmxLJUQguR-W97gIReVDFvaBQUHY7tXxFcflqZ4dU-xR3P7jVPaHdY1&t=fffffffffc18b87d:47
    at HTMLInputElement.onclick (Doc-Comp-Composition-Templates:1)

Controls to validate:

<div class="form-group">
  <label for="ddlCS">Current Status:</label>
  <asp:DropDownList ID="ddlCS" runat="server" CssClass="form-control" 
    ToolTip="Choose Status" Enabled="false" ValidationGroup="gStatusChange" />
</div>
<div class="form-group">
  <label for="ddlNS">New Status:</label>
  <asp:DropDownList ID="ddlNS" runat="server" CssClass="form-control"
    ToolTip="Choose Status" ValidationGroup="gStatusChange" />
</div>
<div class="form-group">
  <label for="ddlPA">Proof Approval:</label>
  <asp:DropDownList ID="ddlPA" runat="server" CssClass="form-control"
     Tooltip="Choose Proof Status" ValidationGroup="gStatusChange" />
</div>

<div class="col-sm-3">
    <asp:Button ID="btnUpdate" runat="server" Text="Update Status" 
         CssClass="btn btn-primary pull-left" ToolTip="Save Changes" 
         OnClick="btnUpdate_Click"/>
</div>

Validator:

<asp:CustomValidator ID="custvStatusChange" runat="server" Display="None" 
      ValidationGroup="gStatusChange"
      ErrorMessage="Wow what an error!"
      OnServerValidate="ValidateStatusChange_ServerValidate"  
      ClientValidationFunction="ValidateStatusChange_ClientValidate"/>
<asp:ValidationSummary ID="vscustvStatusChange" runat="server" ToolTip="Error Summary" 
      ShowSummary="true" 
      ShowMessageBox="false" 
      CssClass="alert alert-danger" 
      ValidationGroup="gStatusChange" />

<Triggers>
     <asp:AsyncPostBackTrigger ControlID="gvTemplates" 
          EventName="RowCommand"/>
     <asp:AsyncPostBackTrigger ControlID="btnUpdate" EventName="Click"/>
</Triggers>

Server-Side Validation:

protected void ValidateStatusChange_ServerValidate(object source, 
   ServerValidateEventArgs args)
    {
        if (ddlCS.SelectedValue == ddlNS.SelectedValue || ddlPA.SelectedIndex == 0)
        {
            args.IsValid = false;
        }
    }

Client-Side Validation:

<script>
    $m = jQuery.noConflict();
</script>
<script type="text/javascript">
    function ValidateStatusChange_ClientValidate(source, args) {
        var cStatus = $(source).ddlCS("select").prop("selectedIndex");
        var nStatus = $(source).ddlNS("select").prop("selectedIndex");
        var pStatus = $(source).ddlPA("select").prop("selectedIndex");

        if (cStatus == nStatus || pStatus == 0) {
            args.IsValid = false;
        } else {
            args.IsValid = true;
        }
    }
    function closeModal() {
        $('#modStatus').modal('hide');
        $('body').removeClass('modal-open');
        $('.modal-backdrop').remove();
    }
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    prm.add_endRequest(function () {

        function closeModal() {
            $('#modStatus').modal('hide');
            $('body').removeClass('modal-open');
            $('.modal-backdrop').remove();
        }
    });
 </script>

Button Click event:

protected void btnUpdate_Click(object sender, EventArgs e)
        {
            Page.Validate("custvStatusChange");
            if (Page.IsValid)
            {
                #region Template Status change
                if (ddlNS.SelectedIndex > 0)
                {
                    if (ddlCS.SelectedValue != ddlNS.SelectedValue)
                    {
                        if (ddlCS.SelectedValue == "5" && hfProofStatus.Value == "N")
                        {
                            lblUpdateStatus.Text = "Proof must be approved before template can be";
                            lblUpdateStatus.CssClass = "text-danger";
                        }
                        else
                        {
                            ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Close", "$('#modStatus').modal('hide');$('body').removeClass('modal-open');$('.modal-backdrop').remove();", true);
                            // save and notify
                            DotNetAuth auth = (DotNetAuth)HttpContext.Current.Session["AppSysAuth"];
                            if (CompositionTemplate.UpdateStatus(Convert.ToInt32(hfTemplateID.Value),
                                Convert.ToInt32(ddlNS.SelectedValue), auth.Name, hfFileName.Value))
                            {
                                lblUpdateStatus.Text = "Status change saved";
                                lblUpdateStatus.CssClass = "text-success";
                                BindGrid();
                            }
                            else
                            {
                                lblUpdateStatus.Text = "Error saving status change";
                                lblUpdateStatus.CssClass = "text-danger";
                            }
                        }
                    }
                }
                #endregion
            }
        }

Solution

  • The ddlCS() function (also with ddlNS() and ddlPA()) is undefined because they're not defined inside jQuery selector of $(source). You should change these lines:

    var cStatus = $(source).ddlCS("select").prop("selectedIndex");
    var nStatus = $(source).ddlNS("select").prop("selectedIndex");
    var pStatus = $(source).ddlPA("select").prop("selectedIndex");
    

    to these lines below, which uses ClientID for each dropdown (since you're not using ClientIDMode="Static" attribute, therefore assumed dynamic client ID is in place):

    var cStatus = $('#<%= ddlCS.ClientID %>').prop("selectedIndex");
    var nStatus = $('#<%= ddlNS.ClientID %>').prop("selectedIndex");
    var pStatus = $('#<%= ddlPA.ClientID %>').prop("selectedIndex");
    

    Or using select element selector with id attribute set to ClientID of each dropdown like this:

    var cStatus = $('select [id=<%= ddlCS.ClientID %>]').prop("selectedIndex");
    var nStatus = $('select [id=<%= ddlNS.ClientID %>]').prop("selectedIndex");
    var pStatus = $('select [id=<%= ddlPA.ClientID %>]').prop("selectedIndex");