I have a payment page that has a name textbox (txtName), a PIN textbox (txtPin) and two textboxes (txtPaymentDate and txtPaymentTime) containing payment date and time respectively. The page also has a payment button (btnPay). txtName has a RequiredFieldValidator that checks if the field is blank. txtPin has a CustomValidator that checks if the field has a six-digit numeric value. A third CustomValidator makes sure that either both txtPaymentDate and txtPaymentTime are clear, or both of them are selected at the same time. Just one of them can't be selected. All these validation checks need to be on the client side.
While clicking btnPay, it'll check on the client side if txtPaymentDate and txtPaymentTime are selected together. If yes, then the value of txtPaymentDate should be between 01/01/1753 12:00:00 AM and 12/31/9999 11:59:59 PM. If the value is not within the specified dates, an alert message will be displayed and click event cancelled.
If all the above validations are successful, btnPay postback will occur and the server side event of btnPay will be fired.
This is what I want to achieve in the exact order on clicking btnPay:
-
All the validations of the validator controls on client side will take place. If validation of any validator control on client side fails, it'll stop btnPay click event. No need to go to step 2 either.
-
On successful validation of all the validator controls above, a client side validation will check if txtPaymentDate and txtPaymentTime are both selected, and if value of txtPaymentDate is within the specified range. If this validation fails, btnPay click event is stopped too.
-
Only if the above two steps are successful, btnPay postback will occur and the server side event of btnPay will be fired.
What's actually happening while clicking btnPay:
-
None of the "client side" validations of the validator controls are occurring at all. Instead, the "server side" validations of the respective validator controls are occurring.
-
Once step 1 is successfully validated, client side validation to check if value of txtPaymentDate is within specified range is occurring successfully. It's also blocking btnPay click event if this validation is not true, which is good as per requirement.
-
If the above two validations are successful, btnPay postback is taking place successfully firing server side event of btnPay, which too is OK as per requirement.
I want step 1 marked in italics above to occur on client side instead of server side. Only when step 1 is validated successfully on client side, steps 2 and 3 will follow suit as mentioned above.
My aspx page:
<%@ Page Title="" Language="C#" MasterPageFile="~/User.master" AutoEventWireup="true" CodeFile="Payment.aspx.cs" Inherits="Payment" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<script type="text/javascript">
// Test if txtPin is not blank, doesn't contain alphanumeric value and contains exactly six digits.
function Client_ValidatePin(source, arguments) {
arguments.IsValid = /^[0-9]{6}$/.test(arguments.Value);
}
// Test if both txtPaymentDate and txtPaymentTime are selected or none of them at all.
function Client_ValidatePaymentDateTime(source, arguments) {
var paymentDate = document.getElementById("<%=txtPaymentDate.ClientID%>").value;
var paymentTime = document.getElementById("<%=txtPaymentTime.ClientID%>").value;
arguments.IsValid = (paymentDate.length == 0 && paymentTime.length == 0) || (paymentDate.length > 0 && paymentTime.length > 0);
}
function Client_ValidatePage() {
// Test if payment date is less than 01/01/1753 12:00:00 AM or greater than 12/31/9999 11:59:59 PM.
var paymentDate = document.getElementById("<%=txtPaymentDate.ClientID%>").value;
var paymentTime = document.getElementById("<%=txtPaymentTime.ClientID%>").value;
if (paymentDate.length > 0 && paymentTime.length > 0) {
if (paymentDate < "1753-01-01" || paymentDate > "9999-12-31") {
alert('All dates should be between 01/01/1753 12:00:00 AM and 12/31/9999 11:59:59 PM');
return false;
}
}
return true;
}
</script>
<div id="divAlert" role="alert" runat="server">
</div>
<div class="row">
<div class="col-md-9">
<h4>Payment</h4>
<hr />
<div class="form-group row">
<asp:Label ID="Label1" runat="server" class="col-md-2 col-form-label" Text="Name:"></asp:Label>
<div class="col-md-7">
<asp:TextBox ID="txtName" class="form-control" runat="server" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" class="text-danger" ErrorMessage="Name is required!" ControlToValidate="txtName"></asp:RequiredFieldValidator>
</div>
</div>
<div class="form-group row">
<asp:Label ID="Label2" runat="server" class="col-md-2 col-form-label" Text="PIN:"></asp:Label>
<div class="col-md-7">
<asp:TextBox ID="txtPin" class="form-control" runat="server" MaxLength="6"></asp:TextBox>
<asp:CustomValidator ID="PinValidator" runat="server" ControlToValidate="txtPin" ValidateEmptyText="true" ClientValidationFunction="Client_ValidatePin" OnServerValidate="PinValidator_ServerValidate" class="text-danger" Display="Static" ErrorMessage="A 6-digit number is required!"></asp:CustomValidator>
</div>
</div>
<div class="form-group row">
<asp:Label ID="Label3" runat="server" class="col-md-2 col-form-label" Text="Date/Time:"></asp:Label>
<div class="col-md-7">
<div class="form-inline">
<asp:TextBox ID="txtPaymentDate" class="form-control" runat="server" TextMode="Date"></asp:TextBox>
<asp:TextBox ID="txtPaymentTime" class="form-control" runat="server" TextMode="Time"></asp:TextBox>
</div>
<asp:CustomValidator ID="PaymentDateTimeValidator" runat="server" ClientValidationFunction="Client_ValidatePaymentDateTime" OnServerValidate="PaymentDateTimeValidator_ServerValidate" class="text-danger" Display="Static" ErrorMessage="Both dates or none of them are required!"></asp:CustomValidator>
</div>
</div>
<asp:Button ID="btnPay" runat="server" Text="Make Payment" OnClientClick="return Client_ValidatePage()" OnClick="btnPay_Click" />
</div>
</div>
</asp:Content>
My code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Payment : System.Web.UI.Page
{
private bool Server_ValidatePage()
{
// If both payment date and payment time are selected, then check if payment date is not a valid date.
if (!String.IsNullOrEmpty(txtPaymentDate.Text) && !String.IsNullOrEmpty(txtPaymentTime.Text))
{
if (!Utilities.IsValidDateTime(txtPaymentDate.Text))
{
divAlert.Attributes["class"] = "alert alert-danger";
divAlert.InnerText = "All dates should be between 01/01/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.";
return false;
}
}
return true;
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
divAlert.InnerText = string.Empty;
divAlert.Attributes["class"] = "d-none";
}
}
protected void PinValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
try
{
// Test if txtPin is not blank, doesn't contain alphanumeric value and contains exactly six digits.
args.IsValid = System.Text.RegularExpressions.Regex.IsMatch(args.Value, "^[0-9]{6}$");
}
catch (Exception ex)
{
args.IsValid = false;
}
}
protected void PaymentDateTimeValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
try
{
// Test if both txtPaymentDate and txtPaymentTime are selected or none of them at all.
args.IsValid = (txtPaymentDate.Text.Length == 0 && txtPaymentTime.Text.Length == 0) || (txtPaymentDate.Text.Length > 0 && txtPaymentTime.Text.Length > 0);
}
catch (Exception ex)
{
args.IsValid = false;
}
}
protected void btnPay_Click(object sender, EventArgs e)
{
if (Page.IsValid && Server_ValidatePage())
{
// Write code for payment.
// If payment is successful...
divAlert.Attributes["class"] = "alert alert-success";
divAlert.InnerText = "Payment completed successfully.";
}
}
}
Any help on this issue is highly appreciated.
Technology used: Visual Studio 2017, Bootstrap 4.5.0 on Windows 7.
Feel free to ask further if my post is not clear to you.
Regards