CustomValidator not executing on second step of a multi-panel Page - asp.net

I am experiencing a problem with an ASPX page not executing a CustomValidator. The Page consists of 3 ASP Panels which swap visibility for each step in a 3 step process. The first step/panel functions as expected, executing all CustomValidators when I click the submit button. If valid, the button click hides its panel and shows the second panel for step #2 which contains another CustomValidator. When clicking the submit button on this second panel, the CustomValidator never executes and the Page always reports that it IsValid.
I have reproduced this behavior in a small, example app. Here is the relevant code...
Default.aspx
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<h2>
Welcome to ASP.NET!
</h2>
<p>
To learn more about ASP.NET visit www.asp.net.
</p>
<p>
You can also find <a href="http://go.microsoft.com/fwlink/?LinkID=152368&clcid=0x409"
title="MSDN ASP.NET Docs">documentation on ASP.NET at MSDN</a>.
</p>
<asp:Panel ID="Panel1" runat="server" Visible="true">
<div>
<asp:CustomValidator
ID="CustomValidator1"
runat="server"
ControlToValidate="TextBox1"
ValidateEmptyText="true"
Display="Dynamic"
OnServerValidate="CustomValidator1_ServerValidate">
</asp:CustomValidator>
</div>
<div>
<asp:Label ID="Label1" runat="server" Text="Type in anything:" AssociatedControlID="TextBox1" />
<asp:TextBox ID="TextBox1" runat="server" />
</div>
<div>
<asp:Button ID="Button1" runat="server" Text="Show Panel #2" OnClick="Button1_Click" />
</div>
</asp:Panel>
<asp:Panel ID="Panel2" runat="server" Visible="false">
<div>
<asp:CustomValidator
ID="CustomValidator2"
runat="server"
Display="Dynamic"
OnServerValidate="CustomValidator2_ServerValidate">
</asp:CustomValidator>
</div>
<div>
<asp:Button ID="Button2" runat="server" Text="I should cause an Exception..." OnClick="Button2_Click" />
</div>
</asp:Panel>
<asp:Panel ID="Panel3" runat="server" Visible="false">
<p>An exception should have been thrown. :(</p>
</asp:Panel>
</asp:Content>
Default.aspx.cs
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Panel1.Visible = true;
Panel2.Visible = false;
Panel3.Visible = false;
}
protected void Button1_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
Panel1.Visible = false;
Panel2.Visible = true;
Panel3.Visible = false;
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
Panel1.Visible = false;
Panel2.Visible = false;
Panel3.Visible = true;
}
}
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
string userEnteredText = TextBox1.Text;
if (string.IsNullOrEmpty(userEnteredText))
{
CustomValidator1.Text = "Text is required!";
args.IsValid = false;
}
else if (!userEnteredText.ToLower().Equals("anything"))
{
CustomValidator1.Text = "You didn't type 'anything'! ;)";
TextBox1.Text = null;
args.IsValid = false;
}
else
{
args.IsValid = true;
}
}
protected void CustomValidator2_ServerValidate(object source, ServerValidateEventArgs args)
{
throw new Exception("This ServerValidate() method never triggers!");
}
}
I don't understand why the CustomValidator2 method is never executing. Can anyone explain this behaviour?

As you're not setting the ControlToValidate property in your scenario set the property ValidateWhenEmpty to true on the CustomValidator.
The CustomValidator will not be evaluated when the ControlToValidate is blank unless ValidateWhenEmpty is true.
UPDATE:
Ok this was wrong. But do you really need to set visibility of the panels in the Page_Load? You've done it already declaratively in the .aspx.
If you remove it from Page_Load, the validator works. I suppose it does not work if the validator is Visible=false or is inside a containing control that is Visible=false.

You should use ValidationGroup property of the buttons and the corresponding validation controls in each panel.

Related

Custom validator message not displaying

VS2013, WebForms, .NET 4.51
I have a FormView defined and in my EditTemplate I have as follows:
<div class="form-group">
<asp:Label ID="lblClientClassification" CssClass="col-md-2 control-label" runat="server" for="cblClientClassifications" Text="Kind"></asp:Label>
<div class="col-md-5">
<asp:CheckBoxList ID="cblClientClassifications" runat="server"></asp:CheckBoxList>
<asp:CustomValidator ID="cfvClientKinds" runat="server" Display="Dynamic" CssClass="label label-danger" ErrorMessage="XXXX" ValidationGroup="Default" OnServerValidate="cfvClientClassifications_OnServerValidate"></asp:CustomValidator>
</div>
and then in the code behind:
protected void cfvClientClassifications_OnServerValidate(object aSource, ServerValidateEventArgs aArgs)
{
CustomValidator cvCheckBoxKinds = aSource as CustomValidator;
int checkedCount = 0;
if (cvCheckBoxKinds != null)
{
CheckBoxList cblClientClassifications = GuiClientClassificationsFind();
foreach (ListItem listItem in cblClientClassifications.Items)
{
if (listItem.Selected)
{
checkedCount++;
}
}
if (checkedCount == 0)
{
aArgs.IsValid = false;
cvCheckBoxKinds.ErrorMessage = "Select client kind.";
}
}
}
The OnServerValidate is firing and I am getting to set the validator to invalid as well as setting the error message (Page.IsValid is also false as expected). However, the error text is not displaying. When I view the page source I see:
<span id="ctl00_cphMainContent_fvData_cfvClientKinds" class="label label-danger" style="display:none;">XXXX</span>
instead of the error message I set as well as the fact that it is not visible.
Has anyone got any pointers here on how to track this down? I have looked at similar questions of SO but none of the comments seem to apply. Is this related to FormView perhaps?
Try your control without the CssClass="label label-danger" bootstrap first, and use the code below to check your boxes:
protected void cfvClientKinds_ServerValidate(object aSource, ServerValidateEventArgs aArgs)
{
aArgs.IsValid = cblClientClassifications.SelectedItem != null;
cfvClientKinds.ErrorMessage = "Hey! this is a new message";
}
and I guess you call this line before you fire the above event:
protected void btnValidate_Click(object sender, EventArgs e)
{
Page.Validate();
}
In Short, I think that your problem is either related to your way of finding cblClientClassifications checkBoxList or other code that you haven't stated above.
CheckBoxList cblClientClassifications = GuiClientClassificationsFind();
I decided to try out your case and created a new webform added formview and bind it to northwind categories table then inside edititemtemplate I added a checkboxlist and populated it manually. added CustomValidator double clicked it copied your codebehind and it works for me except for the findcontrol part: GuiClientClassificationsFind();
Here is the formview:
<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID" DataSourceID="SqlDataSource1">
<EditItemTemplate>
...
<asp:CheckBoxList ID="cblClientClassifications" runat="server">
<asp:ListItem>Bir</asp:ListItem>
<asp:ListItem>iki</asp:ListItem>
<asp:ListItem>Üç</asp:ListItem>
<asp:ListItem>Dört</asp:ListItem>
</asp:CheckBoxList>
<asp:CustomValidator ID="cfvClientKinds" runat="server" Display="Dynamic" CssClass="label label-danger" ErrorMessage="CustomValidator" OnServerValidate="cfvClientKinds_ServerValidate"></asp:CustomValidator>
<br />
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update" Text="Update" />
<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel" />
</EditItemTemplate>
</asp:FormView>
And codebehind with your code:
protected void cfvClientKinds_ServerValidate(object aSource, ServerValidateEventArgs aArgs)
{
CustomValidator cvCheckBoxKinds = aSource as CustomValidator;
CheckBoxList cblClientClassifications = (CheckBoxList)FormView1.FindControl("cblClientClassifications");
int checkedCount = 0;
if (cvCheckBoxKinds != null)
{
foreach (ListItem listItem in cblClientClassifications.Items)
{
if (listItem.Selected)
{
checkedCount++;
}
}
if (checkedCount == 0)
{
aArgs.IsValid = false;
cvCheckBoxKinds.ErrorMessage = "Select client kind.";
}
}
}
I Ali Shahrokhi's method is shorter and works as well as yours..
protected void cfvClientKinds_ServerValidate(object aSource, ServerValidateEventArgs aArgs)
{
CustomValidator cvCheckBoxKinds = aSource as CustomValidator;
CheckBoxList cblClientClassifications = (CheckBoxList)FormView1.FindControl("cblClientClassifications");
aArgs.IsValid = cblClientClassifications.SelectedItem != null;
cvCheckBoxKinds.ErrorMessage = "Select client kind.";
}
if you check as you entered edititemtemplate in formview you'll see before submitting that your customvalidators span will be there just as you mentioned that's because server hasn't sent it to the client yet somehow.

Why isn't my code-behind working properly?

Here's my code-behind file for a web form. I can't get certain arguments to work properly with my form.
protected void btn_Submit_Click(object sender, EventArgs e)
{//Enter arguments here...
}
protected void btn_Clear_Click(object sender, EventArgs e)
{
Response.Redirect("~/ContentRequest/BMC_PR_Event.aspx", true);
}
protected void ShowForm()
{
Open.Visible = true;
Success.Visible = false;
Failure.Visible = false;
}
protected void ShowSuccess()
{
Open.Visible = false;
Success.Visible = true;
Failure.Visible = false;
}
protected void ShowFailure()
{
Open.Visible = false;
Success.Visible = false;
Failure.Visible = true;
}
}
Here's the code I'm trying to get it to work with...
<asp:Button TabIndex="12" Text="Submit Request" ID="Button1" CssClass="submit" OnClientClick="return validateForm();" runat="server" onclick="btn_Submit_Click"></asp:Button>
<asp:Button TabIndex="13" Text="Clear Fields" ID="Button2" CssClass="clear" UseSubmitBehavior="false" runat="server" onclick="btn_Clear_Click"></asp:Button>
<asp:Label ID="Label1" runat="server"></asp:Label>
</div>
</asp:Panel>
<asp:Panel ID="Success" Visible="false" runat="server">
<div class="message"><p>Your submission was sucessful.</p><p>An email receipt has been sent to the address provided with the details of this request.</p><p>Thank you.</p></div>
</asp:Panel>
<asp:Panel ID="Failure" Visible="false" runat="server">
<div class="message">
<p>There was an error with your request. If this persists, please report your trouble to _OHE Web Strategies.</p>
Not sure what else I can do here...
--Edit--
This is the error I get...
From the code you have pasted, i cannot see a Panel control with the ID 'Open'. Please do one of the following.
If you need another Panel for the 'open' functionality, add another asp:Panel with the is 'Open'
If you have removed the Open panel once you had, remove the code (from code behind in your case) related to that.
Best of luck
James

Cannot perform close/open ASP.Net Ajax ModalPopupExtenders in sequence from server side code

I'm having a problem hiding one ModalPopupExtender and Showing another within the same server-side call.
My app requires user input on some validating conditions. These conditions are evaluated in sequence and when certain conditions are true it requires a user to verify (click yes or no) via a ModalPopupExtender window. If the user clicks Yes, evaluation should continue and if another condition requires user input it should also open a modal dialog - until all conditions are passed.
I've got no problem if only one of the conditions requires input, but if more than one require input, only the first modal is displayed and I can't figure out why. When tracing the code it's clear that the Hide() on the first popup is hit and the Show() on the second popup is hit, but the second popup never shows up.
I've tried to pull out the relevant code blocks here with extreme simplification. It's a really complex project and I may have missed something but I hope it's enough to describe my problem.
Problematic process flow:
User clicks "Continue" -> DoContinue is called -> set conditions flags -> Show first modal popup -> Return to user
User clicks "Yes" -> calls condition 1 Yes click handler (set handled flag, hide modal popup) -> call DoContinue-> re-evaluate conditions flags -> attempt to show second modal popup -> return to user.
The first popup disappears but the second is never shown.
It's only a problem when Hide() is being called on the first modal in the same request where Show() is being called on the second.
MyContainerControl.ascx:
<%# Control Language="C#" AutoEventWireup="true" Inherits="MyContainerControl" %>
<input Type="Submit"
id="btnContinue"
Name="btnContinue"
Value="Continue"
OnServerClick="Continue_Click"
runat="server"/>
<asp:UpdatePanel
ID="updateCondition1"
runat="server"
ChildrenAsTriggers="false" UpdateMode="Conditional">
<ContentTemplate>
<ajaxToolkit:ModalPopupExtender
ID="modalCondition1"
runat="server"
BehaviorID="dlgCondition1"
TargetControlID="btnFakeInvokeModalCondition1"
PopupControlID="divCondition1"
BackgroundCssClass="modalBackground"
DropShadow="true"
PopupDragHandleControlID="divDragCondition1"
RepositionMode="RepositionOnWindowResize"
CancelControlID="btnCondition1No" />
<input type="button"
id="btnFakeInvokeModalCondition1"
runat="server"
style="display: none" />
<div id="divCondition1"
runat="server"
class="modalPopup">
<custom:Condition1Control id="condition1" runat="server" visible="false" />
<div id="divDragCondition1"></div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel
ID="updateCondition2"
runat="server"
ChildrenAsTriggers="false" UpdateMode="Conditional">
<ContentTemplate>
<ajaxToolkit:ModalPopupExtender
ID="modalCondition2"
runat="server"
BehaviorID="dlgCondition2"
TargetControlID="btnFakeInvokeModalCondition2"
PopupControlID="divCondition2"
BackgroundCssClass="modalBackground"
DropShadow="true"
PopupDragHandleControlID="divDragCondition2"
RepositionMode="RepositionOnWindowResize"
CancelControlID="btnCondition2No" />
<input type="button"
id="btnFakeInvokeModalCondition2"
runat="server"
style="display: none" />
<div id="divCondition2"
runat="server"
class="modalPopup">
<custom:Condition2Control id="condition2" runat="server" visible="false" />
<div id="divDragCondition2"></div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
MyContainerControl.cs:
public class MyContainerControl : System.Web.UI.UserControl
{
protected HtmlInputImage btnContinue;
//Condition1
protected AjaxControlToolkit.ModalPopupExtender modalCondition1;
protected UpdatePanel updateCondition1;
protected HtmlGenericControl divCondition1;
protected Condition1Control condition1;
//Condition2
protected AjaxControlToolkit.ModalPopupExtender modalCondition2;
protected UpdatePanel updateCondition2;
protected HtmlGenericControl divCondition2;
protected Condition2Control condition2;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
condition1.Condition1RaisedEvent += HandleCondition1Event;
condition2.Condition2RaisedEvent += HandleCondition2Event;
btnContinue.ServerClick += btnContinue_ServerClick;
}
protected void HandleCondition1Event(object sender, Condition1EventArgs e)
{
// use ship to store
ViewState["Condition1Yes"] = true;
ViewState["Condition1Value"] = e.Condition1Value;
modalCondition1.Hide();
DoContinue(sender);
}
protected void HandleCondition2Event(object sender, Condition2EventArgs e)
{
// use ship to store
ViewState["Condition2Yes"] = true;
ViewState["Condition2Value"] = e.Condition2Value;
modalCondition2.Hide();
DoContinue(sender);
}
protected void btnContinue_ServerClick(object sender, EventArgs e)
{
DoContinue(sender);
}
protected void DoContinue(object sender)
{
// test for conditions - just plug to true for demonstration
bool throwCondition1 !(ViewState["Condition1Yes"] == null ? false : (bool)ViewState["Condition1Yes"])
bool throwCondition2 = !(ViewState["Condition2Yes"] == null ? false : (bool)ViewState["Condition2Yes"])
// analyze conditions
if (throwCondition1)
{
var condition1Yes = ViewState["Condition1Yes"] == null ? false : (bool)ViewState["Condition1Yes"];
if (!condition1Yes)
{
divCondition1.Visible = true;
modalCondition1.Show();
return;
}
}
if (throwCondition2)
{
var condition2Yes = ViewState["Condition2Yes"] == null ? false : (bool)ViewState["Condition2Yes"];
if (!condition2Yes)
{
divCondition2.Visible = true;
modalCondition1.Show();
return;
}
}
// do other work
}
}
Condition1UI.ascx - Condition2UI.ascx is very similar:
<%# Control Language="C#" AutoEventWireup="true" Inherits="Condition1Control" %>
<div id="divCondition1Container" runat="server">
<input id="hdnCondition1Value" type="hidden" runat="server" value="<%# this.Condition1Value %>" />
<asp:Panel ID="pnlCondition1UI" runat="server">
<br />
<h2>
Warning!</h2>
<hr />
<br />
<div>
<p>Condition1 has been met.</p>
<br />
<br />
<p>Would you like to continue?</p>
</div>
<br />
<br />
</asp:Panel>
<div>
<table>
<tr>
<td align="center">
<asp:Button ID="btnCondition1Yes" runat="server" class="green" Text="Yes" style="padding: 3px 7px;" OnClick="DoCondition1YesClick" OnClientClick="$find('dlgCondition1').hide();" />
</td>
<td align="center">
<button id="btnCondition1No" class="red">No</button>
</td>
</tr>
</table>
<br />
</div>
<br />
</div>
Condition1Control.cs - Condition2Control.cs is almost identical:
public class Condition1EventArgs : EventArgs
{
public string Condition1Value { get; set; }
}
public class Condition1Control : System.Web.UI.UserControl
{
public HtmlInputHidden Condition1Value;
public event EventHandler<Condition1EventArgs> Condition1RaisedEvent;
protected virtual void RaiseCondition1Event(Condition1EventArgs e)
{
EventHandler<Condition1EventArgs> handler = Condition1RaisedEvent;
if (handler == null)
{
return;
}
handler(this, e);
}
public void DoCondition1ButtonYesClick(object sender, EventArgs e)
{
RaiseCondition1Event(new Condition1EventArgs{
Condition1Value = Condition1Value.Value
});
}
}
Change UpdatePanel's UpdateMode property to "Always" or don't forget to call 'Update' method of UpdatePanel which UI you want to update as result of postback fired from another UpdatePanel. So try to add updateCondition2.Update method call after modalCondition2.Show method in your code.

how to disable server side validation on asp.net web forms from browser?

I wanted to disable asp.net validation server controls from browser. I checked online but did not find any way to disable the server side validation; it can be disabled only on the client side using JS/jQuery.
Here is the scenario: I have a checkbox and selecting which displays a set of text boxes. Only if the checkbox is checked, required field validator should fire for the text boxes. I don't want to call a postback on checkbox. Actually those chceck boxes will be generated with jQuery templating so postback is not an option to enable disable validtion.
I would like to know whether there is any way we can enable disable the .CausesValidation property for the controls from browser using some setting? Or is there a way to capture the controls which are to be considered for validation slectively in some event before page_load?
[Update]
Based on Accepted answer, here is my solution:
<form id="form1" runat="server">
<div>
<asp:TextBox ID="textbox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="req1" ControlToValidate="textbox1" runat="server"
ErrorMessage="enter text"></asp:RequiredFieldValidator>
<asp:TextBox ID="textbox2" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="req2" ControlToValidate="textbox2" runat="server"
ErrorMessage="enter text for 2"></asp:RequiredFieldValidator>
<asp:CheckBox ID="check1" runat="server" Text="choose" />
<asp:Button ID="submitBtn" runat="server" OnClick="submitBtn_Click" Text="submit" />
<asp:CustomValidator ID="cvBox" runat="server" ErrorMessage="Error" ValidationGroup="prueba"
OnServerValidate="Validarcaja"></asp:CustomValidator>
<asp:ValidationSummary ID="summary" runat="server" />
</div>
</form>
protected void Page_Load(object sender, EventArgs e)
{
req1.Enabled = false;
req2.Enabled = false;
}
protected void submitBtn_Click(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
Page.Validate();
if (Page.IsValid)
{
Response.Write("valid form");
}
else
{
Response.Write("invalid form");
}
}
}
protected void Validarcaja(object source, ServerValidateEventArgs args)
{
if (check1.Checked)
{
req1.Enabled = true;
req1.Validate();
}
}
The solution for me would be to use a CustomValidator with a OnServerValidate method.
In the OnServerValidate method I would check if the checkbox is checked, in that case I would verify if the textboxes are filled. It is not necessary to do any change in the CausesValidation property.
The only condition is not to include the property "ControlToValidate". A CustomValidator does not fire if the textbox is empty that's why.
So the code would be like this:
<asp:ValidationSummary ID="vs" runat="server" ValidationGroup="prueba" />
<asp:CheckBox ID="chb" runat="server" Text="Check" />
<asp:TextBox ID="txbBox" runat="server"></asp:TextBox>
<asp:CustomValidator ID="cvBox" runat="server" ErrorMessage="Error" ValidationGroup="prueba"
OnServerValidate="Validarcaja"></asp:CustomValidator>
<asp:Button ID="btn" runat="server" Text="Prueba" />
And the codebehind:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
Page.Validate();
}
}
protected void Validarcaja(object source, ServerValidateEventArgs args)
{
if (chb.Checked)
{
if (txbBox.Text == String.Empty)
{
cvBox.IsValid = false;
}
}
}

ASP.Net: Ajax registration question

I worked with: ASP.Net: Ajax check for registration as a user?
It has a few errors, I don't understand:
1) It worked only one time for one textbox. If the textbox is edited a second time, the breakpoint will not be hited. Why?
2) For my Email, I have a check, that there is no duplicate, when there is one, there should the set an error panel visible, but it don't show.
protected void txtEMail_TextChanged(object sender, EventArgs e)
{
Business.UserHandling uh = new Business.UserHandling();
if (uh.CheckIfEmailExists(txtEMail.Text))
{
panelHelp.Visible = true;
lblHelp.Text = "EMail existriert schon.";
}
}
When the update mode is conditional
<asp:scriptmanager runat="server" id="sm1" />
<asp:updatepanel runat="server" id="up1" updatemode="Conditional"> // here the updatemode is conditional ...
<contenttemplate>
<asp:textbox runat="server" id="tbUsername" autopostback="true" ontextchanged="tbUsername_TextChanged" />
<asp:customvalidator runat="server" text="Email already used" id="cusValEmail" />
<asp:textbox runat="server" id="tbPassword" />
</contenttemplate>
</asp:updatepanel>
You need to call
protected void txtEMail_TextChanged(object sender, EventArgs e)
{
Business.UserHandling uh = new Business.UserHandling();
if (uh.CheckIfEmailExists(txtEMail.Text))
{
panelHelp.Visible = true;
lblHelp.Text = "EMail existriert schon.";
}
up1.Update(); // call to update the update panel "up1"
}
Sorry I'm a bit rusty, it's a while since I've used update panels.
After an update panel updates you must reinitialise the javascript on the html elements inside it.
So, to the end of your method you could add:
protected void txtEMail_TextChanged(object sender, EventArgs e)
{
Business.UserHandling uh = new Business.UserHandling();
if (uh.CheckIfEmailExists(txtEMail.Text))
{
panelHelp.Visible = true;
lblHelp.Text = "EMail existriert schon.";
}
// Re-init javascript
ScriptManager.RegisterStartupScript(Type, String, "add onchange js here", Boolean);
}
see http://msdn.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.registerstartupscript.aspx

Resources