SharePoint 2010 A custom fieldtype for Hyperlinks

In my previous post you already read about custom fieldtypes. Now i just summarize step by step how to build such a custom fieldtype and what possibilities are there from developer view.

My posts about custom fieldtypes:

Ok, let’s start with a really easy example. We want to implement a fieldtype as URL. This Url should open the website in a new window or new tab. I know if you use the normal field type for hyperlinks, it opens the page in a new window if you are in display mode of the item, but it does not if you are in listview. I also know you can customize the listview with xsl so that there is no need for developing this custom fieldtype. There is no need to develop this custom fieldtype. Sounds good. Why we are doing this now?

Well, it is a pretty example of how to create custom fieldtypes and define the listview for this fieldtype and to see what options are available. If you are not interested into how to create a custom fieldtype for Textfields, E-Mail Validation or CRM data queries, then you should read on 🙂 Let’s start.

Create a visual studio project and add some mapped folder:

  • Controltemplates
  • XML

Step 1:  Create the fieldtype definition

Add a .xml file to the XML Folder and call it fldtypes_SPHyperlinkField.xml. It is important that the filename starts with “fldtypes_”

Add the following lines of code:



<fieldtypes>
<fieldtype>
<field Name="TypeName">SPHyperlinkField</field>
<field Name="ParentType">URL</field>
<field Name="TypeDisplayName">SPHyperlinkField</field>
<field Name="TypeShortDescription">SPHyperlinkField (Opens Hyperlink in a new Window)</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="AllowBaseTypeRendering">TRUE</field>
<field Name="Filterable">TRUE</field>
<field Name="Sortable">TRUE</field>
<field Name="FieldTypeClass">SPHyperLinkField.SPHyperLinkField,$SharePoint.Project.AssemblyFullName$</field>
</fieldtype>
</fieldtypes>


Important Note: Write FieldType and Field always with a starting capital letter. Not fieldtype, not Fieldtype, not fieldType – correct FieldType!

Step 2: Create the fieldtype class

Add to your project a class file and call it SPHyperLinkField.cs.



namespace SPHyperLinkField
{
class SPHyperLinkField : SPFieldUrl
{
public SPHyperLinkField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
this.DisplayFormat = SPUrlFieldFormatType.Hyperlink;
}

public SPHyperLinkField(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
this.DisplayFormat = SPUrlFieldFormatType.Hyperlink;
}
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl fieldControl = new SPHyperLinkFieldControl();
fieldControl.FieldName = this.InternalName;
return fieldControl;
}
}
}
}


We create our fieldtype from type SPFieldUrl.

Step 3: Create the fieldtype Control Class

The control class is where we put a great part of our logic into. Add a class file to your project and call it SPHyperLinkFieldControl.cs.



namespace SPHyperLinkField
{
class SPHyperLinkFieldControl : BaseFieldControl
{
protected TextBox txt_url;
protected TextBox txt_desc;
protected HyperLink MySPLink;

protected override string DefaultTemplateName
{
get
{
//Here we define our Controltemplate Name, this is defined in the .ascx file of your Controltemplatefolder
if (this.ControlMode == SPControlMode.Display)
return "SPHyperLinkFieldDisplay";
else
return "SPHyperLinkFieldNew";
}
}

public override object Value
{
//here we set or get the value of the field
get
{
this.EnsureChildControls();
if (string.IsNullOrEmpty(txt_url.Text))
return new SPFieldUrlValue();

SPFieldUrlValue mcv = new SPFieldUrlValue();
mcv.Url = txt_url.Text;
mcv.Description = txt_desc.Text;

return mcv;
}
set
{
this.EnsureChildControls();
if (this.ControlMode == SPControlMode.New || this.ControlMode == SPControlMode.Edit)
{
SPFieldUrlValue mcv = (SPFieldUrlValue)this.ItemFieldValue;
txt_url.Text = mcv.Url;
txt_desc.Text = mcv.Description;
}
else
{
SPFieldUrlValue mcv = (SPFieldUrlValue)this.ItemFieldValue;
MySPLink.NavigateUrl = mcv.Url;
MySPLink.Text = mcv.Description;
}
}
}

protected override void CreateChildControls()
{
base.CreateChildControls();

if (this.ControlMode == SPControlMode.New || this.ControlMode == SPControlMode.Edit)
{
//Here we want to find the control in our template
txt_url = this.TemplateContainer.FindControl("txt_url") as TextBox;
txt_desc = this.TemplateContainer.FindControl("txt_desc") as TextBox;
}
else
{
MySPLink = this.TemplateContainer.FindControl("MySPLink") as HyperLink;
}
}
}
}


Important at this point is that we save and get the values in a correct way and that it is working. We can also define how the field is displayed in Display, New or Edit Mode of the form.

Step 4: Create the Controltemplate

Now add a new item to the mapped folder to Controltemplates. Add a user control and call it SPHyperLinkField.ascx.

In this file we will define what the field will look like – add textboxes or buttons to the control. Important note: The ID of the Rendering Template we are going to define are used in the Field Control class. If they are not the same, the control class won’t find the controls like textbox. We can define foreach display mode (Display, New, Edit) a rendering template. But in this case we only define the New which is also the same to Edit and the Display template. You can delete the file which are below your ascx-file. Keep in mind to delete also the mapping in the ascx file.



< %@ 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="SPHyperLinkFieldNew" runat="server">
<template>
<table>
<tr>
<td>Url: </td>
<td><asp:textbox ID="txt_url" runat="server"></asp:textbox> </td>
</tr>
<tr>
<td>Beschreibung:</td>
<td><asp:textbox ID="txt_desc" runat="server"></asp:textbox>  </td>
</tr>
</table>
</template>
</sharepoint:renderingtemplate>
<sharepoint:renderingtemplate ID="SPHyperLinkFieldDisplay" runat="server">
<template>
<asp:hyperlink runat="server" ID="MySPLink" Target="_blank" Text="MyTest"></asp:hyperlink>
</template>
</sharepoint:renderingtemplate>


Step 5: Deploy and test

Now let’s have a look at our current solution and how it look like in the UI.

New or Edit form:

Display form:

Listview:

Step 6: Create the XSL Rendering for Listview

Now we have our custom fieldtype working, but it opens the link in the same window, when we click in the list view on the link. So how can we achieve that this field type will be rendered in a different way in the listview? As mentioned above, we want that the hyperlink opens in a new tab or a new window. So add a mapped Folder to your solution and map it to the XSL Folder below _layouts/XSL. Then add  to your XSL folder(mapped) a .xslt file and call it fldtypes_SPHyperLinkField.xsl. Important: the file has to end with .XSL not XSLT! In this file we make a reference to the fieldtype. SharePoint will recognize it and knows that it should handle the SPHyperLinkField in this way we define it.



<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[@FieldType='SPHyperlinkField']" mode="URL_body" >
<xsl:param name="thisNode" select="."></xsl:param>
<xsl:variable name="propWindow" select="./@*[name()=current()/@NewWindow]"></xsl:variable>
<xsl:variable name="url" select="substring-before($thisNode/@*[name()=current()/@Name],',')"></xsl:variable>
<xsl:variable name="desc" select="$thisNode/@*[name()=concat(current()/@Name, '.desc')]"></xsl:variable>
<xsl:choose>
<xsl:when test="$propWindow='No'">
<a href="{$url}" target="_self"><xsl:value -of select="$desc"></xsl:value></a>
</xsl:when>
<xsl:otherwise>
<a href="{$url}" target="_blank">
<xsl:value -of select="$desc"></xsl:value>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>


In this example we get the values and split them, so that we can build our hyperlink with the target=”_blank” attribute. Just deploy and test it. Now the link will be opened in a new window or a new tab.

Step 7: More Options

There are many more options which you can handle with custom fieldtypes. You can add Validation to your field. That means, if the user input is not as expected it comes up with a message, what the field expects as values. In this case for example you could validate wether it is a valid url with http:// and www. and .de or .com. There a plenty of examples for this in the web. Therefore i am not going to describe it here.

Resumee: What can you do with custom fieldtypes? Well, what can not do with custom fieldtypes would be the question, right? At first let me tell you that there is no need to do everything with custom fieldtypes. SharePoint offers lots of features and capabilities, but sometimes you just need them.

Examples:

  • E-Mail Validation
  • United State Adress Input, or other Adress Input with multvalue columns
  • CRM Requests
  • Queries against a database
  • Lookup Fields to TopLevel site columns
  • Filtered Lookup Fields
  • Cascaded Lookup Fields

Do you have some more examples? I would like to hear them!

Hope this helps you a little bit to start with custom fieldtypes.

..:: I LIKE SHAREPOINT ::..

The article or information provided here represents completely my own personal view & thought. It is recommended to test the content or scripts of the site in the lab, before making use in the production environment & use it completely at your own risk. The articles, scripts, suggestions or tricks published on the site are provided AS-IS with no warranties or guarantees and confers no rights.

Karsten Pohnke About Karsten Pohnke
He is Consultant for SharePoint Solutions for collaboration, communication and business processes. He provides his customers applications based on standard features as well as development or combining the power of several microsoft tools like Dynamics CRM. In his free time he tries to collect tipps and worthy experience in this blog.

15 comments on “SharePoint 2010 A custom fieldtype for Hyperlinks

  1. Hi,

    Is it the Custom Field Type with Hyperlink works in SP 2013?

    Thank you

    Sri

    • Hi Sri,
      i am not sure, but it should work. Maybe you have to change from 14 hive to 15hive. But SP2013 also contains the 14 hive therefore it should work also in SP2013.

      Karsten

  2. Hi Mate

    I keeping this error message.
    Exception type: SPException
    Exception message: Field type SPHyperlinkField is not installed properly. Go to the list settings page to delete this field.
    at Microsoft.SharePoint.SPFieldCollection.CreateNewFieldInternal(String typeName, String displayName)
    at Microsoft.SharePoint.ApplicationPages.FieldNewPage.Save()
    at Microsoft.SharePoint.ApplicationPages.FieldNewPage.BtnOk_Click(Object sender, EventArgs e)
    at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

    Can you advice?????

    • hi mayank,
      please post your fieldtype xml content. I guess it maybe a case sensitive error or maybe you didn’t call your file fldtypes_name.xml?
      regards
      Karsten

  3. thanks for looking into this. I was having issues where the code could not resolve Textbox etc has types so I included using System.Web.UI.WebControls;

    SPHyperLinkField
    URL
    SPHyperlinkField
    SPHyperlinkField (Opens Hyperlink in a new Window)
    TRUE
    TRUE
    TRUE
    TRUE
    TRUE
    TRUE
    TRUE
    TRUE
    CustomHyperlinkFieldType.SPHyperLinkField,$SharePoint.Project.AssemblyFullName$

    ————————–

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace CustomHyperlinkFieldType
    {
    class SPHyperLinkField : SPFieldUrl
    {
    public SPHyperLinkField(SPFieldCollection fields, string fieldName)
    : base(fields, fieldName)
    {
    this.DisplayFormat = SPUrlFieldFormatType.Hyperlink;
    }

    public SPHyperLinkField(SPFieldCollection fields, string typeName, string displayName)
    : base(fields, typeName, displayName)
    {
    this.DisplayFormat = SPUrlFieldFormatType.Hyperlink;
    }
    public override BaseFieldControl FieldRenderingControl
    {
    get
    {
    BaseFieldControl fieldControl = new SPHyperLinkFieldControl();
    fieldControl.FieldName = this.InternalName;
    return fieldControl;
    }
    }
    }
    }

    ——-

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.UI.WebControls;

    namespace CustomHyperlinkFieldType
    {
    class SPHyperLinkFieldControl : BaseFieldControl
    {
    protected TextBox txt_url;
    protected TextBox txt_desc;
    protected HyperLink MySPLink;

    protected override string DefaultTemplateName
    {
    get
    {
    //Here we define our Controltemplate Name, this is defined in the .ascx file of your Controltemplatefolder
    if (this.ControlMode == SPControlMode.Display)
    return “SPHyperLinkFieldDisplay”;
    else
    return “SPHyperLinkFieldNew”;
    }
    }

    public override object Value
    {
    //here we set or get the value of the field
    get
    {
    this.EnsureChildControls();
    if (string.IsNullOrEmpty(txt_url.Text))
    return new SPFieldUrlValue();

    SPFieldUrlValue mcv = new SPFieldUrlValue();
    mcv.Url = txt_url.Text;
    mcv.Description = txt_desc.Text;

    return mcv;
    }
    set
    {
    this.EnsureChildControls();
    if (this.ControlMode == SPControlMode.New || this.ControlMode == SPControlMode.Edit)
    {
    SPFieldUrlValue mcv = (SPFieldUrlValue)this.ItemFieldValue;
    txt_url.Text = mcv.Url;
    txt_desc.Text = mcv.Description;
    }
    else
    {
    SPFieldUrlValue mcv = (SPFieldUrlValue)this.ItemFieldValue;
    MySPLink.NavigateUrl = mcv.Url;
    MySPLink.Text = mcv.Description;
    }
    }
    }

    protected override void CreateChildControls()
    {
    base.CreateChildControls();

    if (this.ControlMode == SPControlMode.New || this.ControlMode == SPControlMode.Edit)
    {
    //Here we want to find the control in our template
    txt_url = this.TemplateContainer.FindControl(“txt_url”) as TextBox;
    txt_desc = this.TemplateContainer.FindControl(“txt_desc”) as TextBox;
    }
    else
    {
    MySPLink = this.TemplateContainer.FindControl(“MySPLink”) as HyperLink;
    }
    }
    }
    }

    ——

  4. //
    //
    //
    //SPHyperLinkField
    //URL
    //SPHyperlinkField
    //SPHyperlinkField (Opens Hyperlink in a new Window)
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //CustomHyperlinkFieldType.SPHyperLinkField,$SharePoint.Project.AssemblyFullName$
    //
    //


  5. //
    //
    //
    //SPHyperLinkField
    //URL
    //SPHyperlinkField
    //SPHyperlinkField (Opens Hyperlink in a new Window)
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //TRUE
    //CustomHyperlinkFieldType.SPHyperLinkField,$SharePoint.Project.AssemblyFullName$
    //
    //

    </code

  6. Replace [ with
    [FieldTypes>
    [FieldType>
    [Field Name=”TypeName”>SPHyperLinkField
    [Field Name=”ParentType”>URL
    [Field Name=”TypeDisplayName”>SPHyperlinkField
    [Field Name=”TypeShortDescription”>SPHyperlinkField (Opens Hyperlink in a new Window)
    [Field Name=”UserCreatable”>TRUE
    [Field Name=”ShowOnListCreate”>TRUE
    [Field Name=”ShowOnSurveyCreate”>TRUE
    [Field Name=”ShowOnDocumentLibraryCreate”>TRUE
    [Field Name=”ShowOnColumnTemplateCreate”>TRUE
    [Field Name=”AllowBaseTypeRendering”>TRUE
    [Field Name=”Filterable”>TRUE
    [Field Name=”Sortable”>TRUE
    [field Name=”FieldTypeClass”>CustomHyperlinkFieldType.SPHyperLinkField,$SharePoint.Project.AssemblyFullName$
    [/FieldType>
    [/FieldTypes>

    • couldn’t see a possible error source, so i uploaded the visual studio project for you. Maybe it’s easier for you to get it working. The solution worked in my sharepoint without any errors.
      Visual Studio file Let me know if you found the source of the error.

  7. Thanks Karsten. The project works perfectly fine. Not sure what the issue is. At the Display Form of Step 5, the link doesnt open in new window. Only at the List View step it opens in new window.

    Is it possible to have this field as a content type similar to “Link to a Document” content type. I want to have links to external documents in a document library, but appear similar to the name field. Basically has the “Link to a document” link open in a new window. I have managed to do this with javacript, though was looking for a more robust solution like yours.
    Even if there is a way to override the “Link to a document” content type perhaps.

    Thanks for your help.

    • Hi mayank,
      you’re welcome.
      you could create a content type which inherits from the “Link to a Document” content type and set your custom fieldtype as one of the fields. But i am not sure if i exactly understood what you want. I understood that you want to have a link to an “external” document (anywhere) and this should open in a new window. So the link redirects to the form of the document?

  8. Hi

    In the document library I have bunch of excel files and bunch of links to external documents e.g. http://google.com.au/bla.pdf. I want so that when the link is clicked it opens in the new window. “Link to a Document” open the link in the same window. I have some javacript which reads the title and it has ext in it, i use js to open the link in the new window.
    I would of using your field instead of “Link to a Document”. Apprently using the mouse wheel is too hard !!!
    If I add custom fieildtype as field, it appears as a column not under the title column.

  9. Hi,

    nice tutorial, but where does the @NewWindow in the XSLT come from? Is it possible for the user to set its value in the column properties (PropertySchema)?

    Kind regards

    • Hi,
      the @NewWindow in the xslt is there by default. It’s a copy of the default xslt.
      The value whether it should open in a new window or not can be set in the column properties. You have to add code for that. There are some examples out in the www. Let me know if you have done this.
      kind regards

Submit comment

Allowed HTML tags: <a href="http://google.com">google</a> <strong>bold</strong> <em>emphasized</em> <code>code</code> <blockquote>
quote
</blockquote>

Please fill in the captcha: * Time limit is exhausted. Please reload CAPTCHA.