Sunday, 7 February 2010

A Slightly Improved Password Field Template

I know my previous password field template was just about functional, so I have improved it slightly now you will have to enter the password twice in password mode and they will have to match. And in Read-Only mode it just displays ********** or as many ‘*’ as you like.Happy

<asp:Literal runat="server" ID="Literal1" Text="**********" />

Listing 1 - Password.ascx page and the code behind is even less interesting.

<%@ Control 
    Language="C#" 
    CodeFile="Password_Edit.ascx.cs" 
    Inherits="Password_EditField" %>
    
<asp:TextBox 
    ID="TextBox1" 
    runat="server" 
    TextMode="Password" 
    CssClass="droplist">
</asp:TextBox>
<asp:HiddenField 
    ID="HiddenField1" 
    runat="server" 
    Value='<%# GetValue() %>' />
<asp:CompareValidator 
    ID="CompareValidator1" 
    runat="server" 
    ControlToValidate="TextBox1" 
    ControlToCompare="TextBox2" 
    EnableClientScript="true"
    SetFocusOnError="True"
    Text="*" />
<asp:RequiredFieldValidator 
    runat="server" 
    ID="RequiredFieldValidator1" 
    CssClass="droplist"
    ControlToValidate="TextBox1" 
    Display="Dynamic" 
    Enabled="false" 
    Text="*" />
<asp:RegularExpressionValidator 
    runat="server" 
    ID="RegularExpressionValidator1" 
    CssClass="droplist"
    ControlToValidate="TextBox1" 
    Display="Dynamic" 
    Enabled="false" 
    Text="*" />
<asp:DynamicValidator 
    runat="server" 
    ID="DynamicValidator1" 
    CssClass="droplist" 
    ControlToValidate="TextBox1"
    Display="Dynamic" 
    Text="*" />
<br />
<asp:TextBox 
    ID="TextBox2" 
    runat="server" 
    TextMode="Password" 
    CssClass="droplist">
</asp:TextBox>

Listing 2 – Password_Edit.ascx

Password

Figure 1 – Password field template.

From Listing 2 and Figure 1 you can see all I’ve done is add a CompareValidator and an extra TextBox to the page. I have configured the CompareValidators two properties to:

ControlToValidate="TextBox1" 
ControlToCompare="TextBox2"

and enabled client script via the EnableClientScript property.

using System;
using System.Collections.Specialized;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Password_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        TextBox1.MaxLength = Column.MaxLength;
        if (Column.MaxLength < 20)
            TextBox1.Columns = Column.MaxLength;
        TextBox1.ToolTip = Column.Description;

        CompareValidator1.ErrorMessage = "passwords must match";

        if (Mode == DataBoundControlMode.Insert)
            SetUpValidator(RequiredFieldValidator1);

        SetUpValidator(RegularExpressionValidator1);
        SetUpValidator(DynamicValidator1);
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
        var original = dictionary[Column.Name];
        // make sure we have some text
        if (TextBox1.Text.Trim().Length > 0)
            dictionary[Column.Name] = ConvertEditedValue(TextBox1.Text);
        else if (HiddenField1.Value.Length > 0)
            dictionary[Column.Name] = HiddenField1.Value;

    }

    public override Control DataControl
    {
        get { return TextBox1; }
    }
}

Listing 3 – Password_Edit.ascx.cs

In Listing 3 we can see that I have set the ErrorMessage property to “passwords must match” as if we use the SetUpValidator it just disables the validator so this will require a little extra work if you want it localised. Also you will note the line:

Updated: I’ve made some changes to deal with the issue of RequiredFieldValidator I’ve added a HiddenField to hold the current password and if no password has been entered during an edit and the field is required I check to see if we have a value in the hidden field (as a validation error for required field will be thrown even if no RequiredFieldValidator is setup or present)
protected override void ExtractValues(IOrderedDictionary dictionary)
{
    var original = dictionary[Column.Name];
    // make sure we have some text
    if (TextBox1.Text.Trim().Length > 0)
        dictionary[Column.Name] = ConvertEditedValue(TextBox1.Text);
}

In the ExtractValues method that check to see if the TextBox is empty ‘if (TextBox1.Text.Trim().Length > 0)’ if it is empty we simply return no value which means the value stays the same.

The only issue is that if you add text to the second TextBox (without entering any text into the first) then validation fails in that no error is flagged, nut no values is saved, so in this case the password would remain the same. I have looked at this and am writing an extended CompareValidator to a) fix this inconsistency and b) give a server side validation event if required.

I wont bother with a download this time as you have all the code in Listings 2 & 3 and you have all you need for the Password.ascx in Listing 1.

Happy Coding

9 comments:

Anonymous said...

not working on chrome

Stephen J. Naughton said...

In what way does it not work :) the only thing I'm doing on the client is set display mode to password on the text boxes.

Steve

Anonymous said...

Chrome still blows

Stephen J. Naughton said...

Yes, you said :) but can you tell me what error you get or what actually happens?

Steve :)

Stephen J. Naughton said...

Just posted a FIX for required field in Edit mode.

Steve :)

Cleyton Messias said...

Why dont you put the solution for download?!

It makes the things easier

Stephen J. Naughton said...

Hi Cleyton, I plan to create a Codeplex project with all my templates in it. And yes you are right I should have posted a sample for this one :(

Steve

MTmace said...

I am getting the following error:
"The name 'GetValue' does not exists in the current context.

MTmace said...

Using .net 4.0 I replaced "GetValue" with "Field Value".