搜尋此網誌

2024年3月19日 星期二

ASP 選擇性啟用 Validator

緣起:


    我有負責一個案子的會員登入頁,不久前為了過無障礙,有幫登入頁的每個 TextBox 都加了一個 ASP 的 RequiredFieldValidator,我用一個簡化的 login 頁面模擬情境




    這是前台的程式碼

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="login.aspx.cs" Inherits="WebApplication1.login" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            Email:<asp:TextBox runat="server" ID="txtEmail"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvEmail" SetFocusOnError="true" ControlToValidate="txtEmail" ForeColor="Red">
                請輸入Email
            </asp:RequiredFieldValidator><br />
            密碼:<asp:TextBox runat="server" ID="txtPassword" TextMode="Password"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvPassword" SetFocusOnError="true" ControlToValidate="txtPassword" ForeColor="Red">
                請輸入密碼
            </asp:RequiredFieldValidator><br />
            認證碼:<asp:TextBox runat="server" ID="txtCheckCode"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvCheckCode" SetFocusOnError="true" ControlToValidate="txtCheckCode" ForeColor="Red">
                請輸入認證碼
            </asp:RequiredFieldValidator><br />
            <asp:Button runat="server" ID="btnSubmit" Text="送出" OnClick="btnSubmit_Click" /><br />
            <asp:Button runat="server" ID="btnForgot" Text="忘記密碼"/><br />
            <asp:Literal runat="server" ID="litResult"></asp:Literal>
        </div>
    </form>
</body>
</html>

    然後這是後台的程式碼

using System;

namespace WebApplication1
{
    public partial class login : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            litResult.Text = $"Email:{txtEmail.Text}, 密碼:{txtPassword.Text}, 認證碼:{txtCheckCode.Text}";
        }
    }
}


問題:


    使用者按下登入時,我們的那幾個 RequiredFieldValidator 都會查看使用者有沒有輸入內容,阻止空值傳到後台,這是符合預期的


    但是呢,我們的 "忘記密碼" 功能,它不會開啟一個獨立的頁面,點下去後,它會依據使用者輸入的 Email,向此 Email 傳送對應的密碼 (如果資料庫有成功找到的話)。所以,在 "忘記密碼" 功能的使用上,使用者只需輸入 Email 跟驗證碼即可。

    但是,由於密碼的 TextBox 有對應的 RequiredFieldValidator 存在,所以會出現提示要我們輸入密碼。


    所以需求就是,在 "忘記密碼" 被使用者點選時,rfvCheckCode 這個 RequiredFieldValidator 不能有作用。


解決:


    主要都是參考這篇文章

    首先是前台 JavaScript 的部份,ASP 的 WebForm 會自動在前台產生一個叫 ValidatorEnable 的 Js function


    可以用這方法來設定 Validator 元件的啟用與否,所以我們寫一個 function 給 btnForgot 的 OnClientClick,當 btnForgot 被點選時,設定 rfvPassword 為不啟用

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="login.aspx.cs" Inherits="WebApplication1.login" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            Email:<asp:TextBox runat="server" ID="txtEmail"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvEmail" SetFocusOnError="true" ControlToValidate="txtEmail" ForeColor="Red">
                請輸入Email
            </asp:RequiredFieldValidator><br />
            密碼:<asp:TextBox runat="server" ID="txtPassword" TextMode="Password"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvPassword" SetFocusOnError="true" ControlToValidate="txtPassword" ForeColor="Red">
                請輸入密碼
            </asp:RequiredFieldValidator><br />
            認證碼:<asp:TextBox runat="server" ID="txtCheckCode"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvCheckCode" SetFocusOnError="true" ControlToValidate="txtCheckCode" ForeColor="Red">
                請輸入認證碼
            </asp:RequiredFieldValidator><br />
            <asp:Button runat="server" ID="btnSubmit" Text="送出" OnClick="btnSubmit_Click" /><br />
            <asp:Button runat="server" ID="btnForgot" Text="忘記密碼" OnClientClick="DisableRfvPassword()"/><br />
            <asp:Literal runat="server" ID="litResult"></asp:Literal>
        </div>
    </form>
    <script type="text/javascript">
        function DisableRfvPassword() {
            let rfvPassword = document.getElementById("<%=rfvPassword.ClientID%>");
            ValidatorEnable(rfvPassword, false);
            return true;
        }
    </script>
</body>
</html>

    run 程式,點擊 "忘記密碼",它就不會提示要我們輸入密碼了


    但當我們輸入完 Email 跟認證碼後再點選 "忘記密碼",頁面 PostBack 回來後,還是會出現沒輸入密碼的提示字


    所以再來是要處理後端的程式。在後台 override Validate 方法 (有傳 string 參數的那個)

using System;

namespace WebApplication1
{
    public partial class login : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public override void Validate(string sValidateGroup)
        {
            if (sValidateGroup.Equals("forgot"))
                rfvPassword.Enabled = false;
            base.Validate();
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            litResult.Text = $"Email:{txtEmail.Text}, 密碼:{txtPassword.Text}, 認證碼:{txtCheckCode.Text}";
        }
    }
}

    14、15行 : 如果 validateGroup 是 "forgot" 的話,那就不啟用 rfvPassword


    然後回到前台頁面,幫 btnForgot 加上 ValidationGroup="forgot"

<asp:Button runat="server" ID="btnForgot" Text="忘記密碼" OnClientClick="DisableRfvPassword()" ValidationGroup="forgot"/><br />

    再開啟頁面,可以發現,當我們只有輸入 Email 跟認證碼後再按 "忘記密碼",它就不會再提示我們說要輸入密碼了


    最後還有一個小問題,就是點完 "忘記密碼" 後再回去點 "送出",密碼欄位就不會被檢查,因為我們在前台跟後台都已經把 rfvPassword 的功能給關閉了。所以,當 "送出" 被點選時,我們應該要啟用 
rfvPassword。

    前台頁面

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="login.aspx.cs" Inherits="WebApplication1.login" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            Email:<asp:TextBox runat="server" ID="txtEmail"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvEmail" SetFocusOnError="true" ControlToValidate="txtEmail" ForeColor="Red">
                請輸入Email
            </asp:RequiredFieldValidator><br />
            密碼:<asp:TextBox runat="server" ID="txtPassword" TextMode="Password"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvPassword" SetFocusOnError="true" ControlToValidate="txtPassword" ForeColor="Red">
                請輸入密碼
            </asp:RequiredFieldValidator><br />
            認證碼:<asp:TextBox runat="server" ID="txtCheckCode"></asp:TextBox>
            <asp:RequiredFieldValidator runat="server" ID="rfvCheckCode" SetFocusOnError="true" ControlToValidate="txtCheckCode" ForeColor="Red">
                請輸入認證碼
            </asp:RequiredFieldValidator><br />
            <asp:Button runat="server" ID="btnSubmit" Text="送出" OnClick="btnSubmit_Click" OnClientClick="EnableRfvPassword"/><br />
            <asp:Button runat="server" ID="btnForgot" Text="忘記密碼" OnClientClick="DisableRfvPassword()" ValidationGroup="forgot"/><br />
            <asp:Literal runat="server" ID="litResult"></asp:Literal>
        </div>
    </form>
    <script type="text/javascript">
        function DisableRfvPassword() {
            let rfvPassword = document.getElementById("<%=rfvPassword.ClientID%>");
            ValidatorEnable(rfvPassword, false);
            return true;
        }

        function EnableRfvPassword() {
            let rfvPassword = document.getElementById("<%=rfvPassword.ClientID%>");
            ValidatorEnable(rfvPassword, true);
        }
    </script>
</body>
</html>

    37~40 行 : 啟用 rfvPassword 的 function。
    25 行 : 為送出按鈕加上啟用 rfvPassword 的 function

    
    然後是後台的程式碼,主要是再加個 else 來啟用 rfvPassword,還有在 btnSubmit_Click 事件裡檢查 Page.IsValid

using System;

namespace WebApplication1
{
    public partial class login : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public override void Validate(string sValidateGroup)
        {
            if (sValidateGroup.Equals("forgot"))
                rfvPassword.Enabled = false;
            else
                rfvPassword.Enabled = true;
            base.Validate();
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            if (!Page.IsValid) return;
            litResult.Text = $"Email:{txtEmail.Text}, 密碼:{txtPassword.Text}, 認證碼:{txtCheckCode.Text}";
        }
    }
}

    16、17行 : 啟用 rfvPassword
    23 行 : Page 沒有 Valid 的話,結束 Button Click 事件


    這樣就完成了 !!

沒有留言:

張貼留言