SharePoint 2010 Custom Field Type: Create US Phone Number Mask in VS2010

Unanswered SharePoint 2010 Custom Field Type: Create US Phone Number Mask in VS2010

  • Wednesday, June 20, 2012 5:23 PM
     
      Has Code

    I'm trying to create a custom field type for use in lists and libraries in SP 2010. It is for a US phone number. The user should be able to only enter numerical numbers, and those numerical numbers must be no more than 10 digits.

    It would be great if I could have a field mask that would display the following during typing:

    New Field: (___) ___-____

    Partial Entry (the way the field looks when user types in the field): (213) 5__-____

    Completed entry: (213) 555-1212

    Or something similar to the above.

    Has anyone else done this for SP?

    Here is my code so far in VS2010:

    SPPhoneFieldControl.ascx

    <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Control Language="C#" %> <SharePoint:RenderingTemplate ID="SPPhoneFieldControl" runat="server"> <Template> <asp:Label ID="SPPhonePrefix" Text="Phone" runat="server" /> &nbsp; <asp:TextBox ID="TextField" runat="server" /> </Template> </SharePoint:RenderingTemplate> <SharePoint:RenderingTemplate ID="SPPhoneFieldControlForDisplay" runat="server"> <Template> <asp:Label ID="SPPhoneValueForDisplay" runat="server" /> </Template> </SharePoint:RenderingTemplate>

    fldtypes_SPPhoneField.xsl

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
                    xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
                    version="1.0"
                    exclude-result-prefixes="xsl msxsl ddwrt"
                    xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
                    xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
                    xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                    xmlns:SharePoint="Microsoft.SharePoint.WebControls"
                    xmlns:ddwrt2="urn:frontpage:internal">
      <xsl:template match="FieldRef[@Name = 'PhoneMask']" mode="Text_body">
        <xsl:param name="thisNode" select="." />
        <span style="background-color:lightgreen;font-weight:bold">
          <xsl:value-of select="$thisNode/@*[name()=current()/@Name]" />
        </span>
      </xsl:template >
    </xsl:stylesheet>

    fldtypes_SPPhone.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <FieldTypes>
      <FieldType>
        <Field Name="TypeName">PhoneMask</Field>
        <Field Name="ParentType">Text</Field>
        <Field Name="TypeDisplayName">PhoneMask</Field>
        <Field Name="TypeShortDescription">Phone Number Mask</Field>
        <Field Name="UserCreatable">TRUE</Field>
        <Field Name="ShowOnListCreate">TRUE</Field>
        <Field Name="ShowOnSurveyCreate">TRUE</Field>
        <Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
        <Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
        <Field Name="FieldTypeClass">Contoso.SharePoint.SPPhoneField, $SharePoint.Project.AssemblyFullName$</Field>
      </FieldType>
    </FieldTypes>

    SPPhone.Field.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Security;
    using System.Windows.Controls;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using Contoso.SharePoint.WebControls;
    using Contoso.System.Windows.Controls;
    namespace Contoso.SharePoint
    {
        class SPPhoneField : SPFieldText
        {
        
            public SPPhoneField(SPFieldCollection fields, string fieldName)
                : base(fields, fieldName)
            {
            }
            public SPPhoneField(SPFieldCollection fields, string typeName, string displayName)
                : base(fields, typeName, displayName)
            {
            }
            public override BaseFieldControl FieldRenderingControl
            {
                [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
                get
                {
                    BaseFieldControl fieldControl = new SPPhoneFieldControl();
                    fieldControl.FieldName = this.InternalName;
                    return fieldControl;
                }
            }
            public override string GetValidatedString(object value)
            {
                if ((this.Required == true)
                   &&
                   ((value == null)
                    ||
                   ((String)value == "")))
                {
                    throw new SPFieldValidationException(this.Title
                        + " must have a value.");
                }
                else
                {
                    SPPhoneValidationRule rule = new SPPhoneValidationRule();
                    ValidationResult result = rule.Validate(value, CultureInfo.InvariantCulture);
                    if (!result.IsValid)
                    {
                        throw new SPFieldValidationException((String)result.ErrorContent);
                    }
                    else
                    {
                        return base.GetValidatedString(value);
                    }
                }
            }// end GetValidatedString
        }
    }

    SPPhone.FieldControl.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Runtime.InteropServices;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    namespace Contoso.SharePoint.WebControls
    {
        class SPPhoneFieldControl : TextField
        {
            protected Label SPPhonePrefix;
            protected Label SPPhoneValueForDisplay;
            protected override string DefaultTemplateName
            {
                get
                {
                    if (this.ControlMode == SPControlMode.Display)
                    {
                        return this.DisplayTemplateName;
                    }
                    else
                    {
                        return "SPPhoneFieldControl";
                    }
                }
            }
            public override string DisplayTemplateName
            {
                get
                {
                    return "SPPhoneFieldControlForDisplay";
                }
                set
                {
                    base.DisplayTemplateName = value;
                }
            }
            protected override void CreateChildControls()
            {
                if (this.Field != null)
                {
                    // Make sure inherited child controls are completely rendered.
                    base.CreateChildControls();
                    // Associate child controls in the .ascx file with the 
                    // fields allocated by this control.
                    this.SPPhonePrefix = (Label)TemplateContainer.FindControl("SPPhonePrefix");
                    this.textBox = (TextBox)TemplateContainer.FindControl("TextField");
                    this.SPPhoneValueForDisplay = (Label)TemplateContainer.FindControl("SPPhoneValueForDisplay");
                    if (this.ControlMode != SPControlMode.Display)
                    {
                        if (!this.Page.IsPostBack)
                        {
                            if (this.ControlMode == SPControlMode.New)
                            {
                                //This needs to be changed
                                textBox.Text = "000-000-0000";
                            } // end assign default value in New mode
                        }// end if this is not a postback 
                        //Do not reinitialize on a postback.
                    }
                    else // control mode is Display 
                    {
                        // Assign current value from database to the label control
                        SPPhoneValueForDisplay.Text = (String)this.ItemFieldValue;
                    }// end control mode is Display
                }// end if there is a non-null underlying ISBNField 
                // Do nothing if the ISBNField is null.
            }
            public override object Value
            {
                get
                {
                    EnsureChildControls();
                    return base.Value;
                }
                set
                {
                    EnsureChildControls();
                    base.Value = (String)value;
                    // The value of the ISBNPrefix field is hardcoded in the
                    // template, so it is not set here.
                }
            }
        }
    }

    SPPhoneValidationRule.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows.Controls;
    using System.Globalization;
    namespace Contoso.System.Windows.Controls
    {
        class SPPhoneValidationRule : ValidationRule
        {
            //Need to update this:
            
            public override ValidationResult Validate(object value, CultureInfo cultureInfo)
            {
                String sPPhone = (String)value;
                String errorMessage = "";
                
                //Need to update this:
                Regex rxSPPhone = new Regex(@"^\([\d_]{3}\)[\d_]{3}-[\d_]{4}$");
                if (!rxSPPhone.IsMatch(sPPhone))
                {
                    //Need to update this:
                    errorMessage = "Phone Numbers must have the format of (000) 000-0000";
                }
                if (errorMessage == "") // Matched the RegEx, so check for group length errors.
                {
                    Match mSPPhone = rxSPPhone.Match(sPPhone);
                    GroupCollection groupsInString = mSPPhone.Groups;
                    //Need to update this:
                    String AreaCode = groupsInString["AreaCode"].Value;
                    String Prefix = groupsInString["Prefix"].Value;
                    String Suffix = groupsInString["Suffix"].Value;
                    if ((AreaCode.Length + Prefix.Length + AreaCode.Length) > 10)
                    {
                        //Need to update this:
                        errorMessage = "The Area Code, Prefix and Suffix cannot be more than 10 digits \n";
                    }
                    String sPPhoneNumber = groupsInString["SPPhoneNumber"].Value;
                    if (((AreaCode.Length + Prefix.Length+Suffix.Length) ) != 10)
                    {
                        errorMessage = errorMessage + "The Area Code, Prefix and Suffix must total exactly 10 digits.\n";
                    }
                    //Need to update this:
                    if (errorMessage == "") //No group length errors, so verify the check digit algorithm.
                    {
                        
                        String sPPhoneNumberNumeric = AreaCode + Prefix + Suffix; //Concatenate without the hyphens.
                     
             // Phone  is invalid if weighted sum modulo 11 is not 0.
                       
                        if (errorMessage == "") // Passed check digit verification. 
                        {
                            return new ValidationResult(true, "This is a valid Phone Mask.");
                        }// end check digit verification passed
                        else // the check digit verification failed
                        {
                            return new ValidationResult(false, errorMessage);
                        }
                    }// end no group length errors
                    else // There was some error in a group length
                    {
                        return new ValidationResult(false, errorMessage);
                    }
                }// end RegEx match succeeded
                else // There was a RegEx match failure
                {
                    return new ValidationResult(false, errorMessage);
                }
            }// end Validate method 
        }// end SPPhone10ValidationRule class
    }


    • Edited by jmcpsd Monday, June 25, 2012 4:19 PM
    •  

All Replies

  • Tuesday, June 26, 2012 6:21 AM
     
     

    Hi imcpsd,

    Thanks for your post!

    I am trying to involve some one familiar with this topic to do some further research.

    Thanks,
    Simon


    Simon Huang

    TechNet Community Support

  • Monday, July 23, 2012 9:35 PM
     
     
    Seems you are close with this, have you considered using client-side validation to get what you are looking for?  There are several examples out there if you search for phone masks.  That way you can just declare the control and have client-side code do the heavy lifting for the validation.

    Patrick Cole - MSFT

  • Thursday, August 02, 2012 10:07 PM
     
     

    I'd prefer to have it as a SharePoint Field type, if possible.

    I think this method would be the simplest way to reuse this over since this will be a common field.