How to create custom field type in SharePoint ?

Business Cases:

Custom field type in SharePoint is very useful solution for many problems and can be used for several times. It used when you need new type of columns which not found in SharePoint out of the box types. Business Cases which you can use like (color field, Attendance Filed, etc.).I will illustrate these types in the next demos.

To implement custom field types in SharePoint you have 2 methods:
§  Using client-side rendering.
§  Using server-side rendering.


Business Cases Details:

First Method (Using client-side rendering)
In this demo I want to create color field type which is a picker in new/edit form and colored div in view/display form.
Demo:
1.    Create the farm solution project and called it CustomColorField.
2.    Add a class for the custom field type.
o    Declares a Color class that inherits from SPFieldText.
o    Provides two constructors for the Color class.
o    Overrides the JSLink property.

using Microsoft.SharePoint;

namespace CustomColorField
{
    public class Color : SPFieldText
    {      
        private const string JsLinkUrl =
            "~site/_layouts/15/Assets/ColorFieldType.js";

        public Color(SPFieldCollection fields, string name)
            : base(fields, name)
        {

        }

        public Color(SPFieldCollection fields, string typename, string name)
            : base(fields, typename, name)
        {

        }
       
        public override string JSLink
        {
            get
            {
                return JsLinkUrl;
            }
            set
            {
                base.JSLink = value;
            }
        }
    }
}

3.    Add an XML definition for the custom field type.
o    Right-click the farm solution project, and add a SharePoint mapped folder. In the dialog box, select the {SharePointRoot}\Template\XML folder.
o    Right-click the XML folder created in the last step, and add a new XML file. Name the XML file fldtypes_ColorFieldType.xml.
o    Copy the following markup, and paste it in the XML file. The markup performs the following tasks:
§  Provides type name for the field type.
§  Specifies the full class name for the field type. This is the class you created in the previous procedure.
§  Provides additional attributes for the field type.

<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">Color</Field>
    <Field Name="TypeDisplayName">color field</Field>
    <Field Name="TypeShortDescription">color field</Field>
    <Field Name="InternalType">Text</Field>
    <Field Name="SQLType">nvarchar</Field>
    <Field Name="FieldTypeClass">CustomColorField.Color, $SharePoint.Project.AssemblyFullName$</Field>
    <Field Name="ParentType">Text</Field>
    <Field Name="Sortable">TRUE</Field>
    <Field Name="Filterable">TRUE</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowOnListCreate">TRUE</Field>
    <Field Name="ShowOnSurveyCreate">TRUE</Field>
    <Field Name="ShowOnDocumentLibrary">TRUE</Field>
    <Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
  </FieldType>
</FieldTypes>


4.    Add a JavaScript file for the rendering logic of the custom field type.
o    Right-click the farm solution project, and add the SharePoint Layouts mapped folder. Add a new Assets folder to the recently added Layouts folder.
o    Right-click the Assets folder that you created in the last step, and add a new JavaScript file. Name the JavaScript file ColorFieldType.js.
o    Creates a template for the field when it is displayed in a view form.
o    Registers the template.
o    Provides the rendering logic for the field type when used displayed in a view form.

(function () {
    var colorContext = {};
    colorContext.Templates = {};
    colorContext.Templates.Fields = {
        "Color"://Field Type Name
            {
                "View": colorViewTemplate,// function to render field in view mode
                "NewForm": colorNewEditTemplate, // function to render field in New form mode
                "DisplayForm": colorViewTemplate,// function to render field in display form mode
                "EditForm": colorNewEditTemplate// function to render field in Edit form mode
            }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(
        colorContext
        );
})();

function colorViewTemplate(ctx) {
    var color = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
    return "<span style='background-color : " + color +
        "' >&nbsp;&nbsp;&nbsp;&nbsp;</span>";
}

function colorNewEditTemplate(ctx) {
    if (ctx == null || ctx.CurrentFieldValue == null)
        return '';
    var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
    if (formCtx == null || formCtx.fieldSchema == null)
        return '';
    //function to register Get Value Callback to make save action read the value of this field from rendering html
    RegisterCallBacks(formCtx);
    //render field in new and edit form
    var html = RenderInputFields(ctx);
    return html;
}

function RenderInputFields(ctx) {
    var html = '<table>';
    html += '<tr>';
    html += '<td><input id="' + "colorField" + '" type="Color" value="' + ctx.CurrentItem[ctx.CurrentFieldSchema.Name] + '" /></td>';
    html += '</tr></table>';
    return html;
}

function RegisterCallBacks(formCtx) {   
    formCtx.registerGetValueCallback(formCtx.fieldName, function () {       
        var colorField = document.getElementById("colorField");
        if (colorField == null)
            return null;
        else {
            return colorField.value;
        }
    });
}



Snapshot from the final solution:





Snapshot from SharePoint server:


 Create Column from color type in list



New Item Form


Display Form

View Form
 Edit Form



Second Method (Using server-side rendering)

In this demo I want to create Attendance field type which is a grid view (have students name's and attendance status for each of them) in new/edit form and label in view/display form.
Demo:
         -    Create the farm solution project and called it CustomAttendanceField.
         -    Add a class for the custom field type.
      o    Declares Attendance class that inherits from SPFieldText.
      o    Provides two constructors for the Color class.

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace CustomAttendanceField
{
    public class Attendance : SPFieldText
    {
        public Attendance(SPFieldCollection fields, string name)
            : base(fields, name)
        {

        }

        public Attendance(SPFieldCollection fields, string typename, string name)
            : base(fields, typename, name)
        {

        }
       
    }
}

      -    Add an XML definition for the custom field type.
      o    Right-click the farm solution project, and add a SharePoint mapped folder. In the dialog box, select                     the {SharePointRoot}\Template\XML folder.
   o    Right-click the XML folder created in the last step, and add a new XML file. Name the XML                                 file fldtypes_AttendanceFieldType.xml.
   o    Copy the following markup, and paste it in the XML file. The markup performs the following tasks:
§  Provides type name for the field type.
§  Specifies the full class name for the field type. This is the class you created in the previous procedure.
§  Provides additional attributes for the field type.


<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">Attendance</Field>
    <Field Name="TypeDisplayName">Attendance field</Field>
    <Field Name="TypeShortDescription">Attendance field</Field>
    <Field Name="InternalType">Text</Field>
    <Field Name="SQLType">nvarchar</Field>
    <Field Name="FieldTypeClass">CustomAttendanceField.Attendance, $SharePoint.Project.AssemblyFullName$</Field>
    <Field Name="ParentType">Text</Field>
    <Field Name="Sortable">TRUE</Field>
    <Field Name="Filterable">TRUE</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowOnListCreate">TRUE</Field>
    <Field Name="ShowOnSurveyCreate">TRUE</Field>
    <Field Name="ShowOnDocumentLibrary">TRUE</Field>
    <Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
  </FieldType>
</FieldTypes>
Note: The file name must begin with fldtypes_
For this example I called it: fldtypes_AttendanceFieldType.xml

1.       Add the User control in a mapped folder on the file "ControlTemplates" directly because SharePoint does not search the subfolders of the folder ControlTemplates for customs field type, it looks only for components in folder ControlTemplates.(in this demo called user control AttendanceControl.ascx)
2.      Delete files ". cs" from control, the only thing we need is the "ascx".
3.      In the ascx file, delete the links to the code behind class of the line “Control”
<%@ Control Language="C#" %>
4.      Add user Control call it UserControl1. To use it in the rendering template for new and edit form.(this control get students name's from SharePoint list).
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.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=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="UserControl1.ascx.cs" Inherits="CustomAttendanceField.CONTROLTEMPLATES.UserControl1" %>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
    <Columns>
        <asp:TemplateField HeaderText="Name">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" Text='<%#Bind("Title") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:DropDownList ID="DropDownList1" runat="server" >
                    <asp:ListItem>Normal</asp:ListItem>
                    <asp:ListItem>Absent</asp:ListItem>
                    <asp:ListItem>Late</asp:ListItem>
                </asp:DropDownList>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
5.      Add "RenderingTemplate" that will be used to display our control in the page "edit item" and "view item". In the first, "AttendanceCustomFieldControl" we will have another user control to retrieve the data. In the second, "AttendanceCustomFieldControlForDisplay" we will have a label to display the field value.
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Src="~/_controltemplates/15/UserControl1.ascx" TagPrefix="uc1" TagName="UserControl1" %>
<%@ Control Language="C#" %>
<SharePoint:RenderingTemplate ID="AttendanceCustomFieldControl" runat="server">
    <Template>
        <table>           
            <tr>
                <td>
                    <uc1:UserControl1 runat="server" id="UserControl1" />
                </td>
            </tr>
        </table>
    </Template>
</SharePoint:RenderingTemplate>
<SharePoint:RenderingTemplate ID="AttendanceCustomFieldControlForDisplay" runat="server">
    <Template>
        <table>
            <tr>
                <td>
                    <asp:Label ID="Label1" runat="server" Text=""></asp:Label>
                </td>
            </tr>
        </table>
    </Template>
</SharePoint:RenderingTemplate>

6.       Add the class definition of control.In this class we will define the behavior of our control, including the possible treatments for display and perform the save. So let’s create our class "AttendanceCustomFieldRendering" which inherits from "BaseFieldControl". In this class we will start by declaring the components of our "RenderingTemplate" label "Label1" and the user control "UserControl1".

using System;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using CustomAttendanceField.CONTROLTEMPLATES;

namespace CustomAttendanceField
{
    public class AttendanceCustomFieldRendering : BaseFieldControl
    {
        protected Label Label1;
        protected UserControl1 UserControl11;

        protected override string DefaultTemplateName
        {
            get
            {               
                if (ControlMode == SPControlMode.Display)
                    return DisplayTemplateName;
                return "AttendanceCustomFieldControl";
            }
        }
       
        public override string DisplayTemplateName
        {
            get
            {
                return "AttendanceCustomFieldControlForDisplay";
            }
            set
            {
                base.DisplayTemplateName = value;
            }
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            Label1 = (Label)TemplateContainer.FindControl("Label1");
            UserControl11 = (UserControl1)TemplateContainer.FindControl("UserControl1");

            if (ControlMode == SPControlMode.Display)
            {
                if (Label1 != null)
                {
                    string fieldValue = (string)ItemFieldValue;
                    if (fieldValue != null)
                    {
                        string[] items = fieldValue.Split('#');
                        Label1.Text += "<table>";
                        foreach (string item in items)
                        {
                            Label1.Text += "<tr>";
                            string[] arr = item.Split(',');
                            foreach (string s in arr)
                            {
                                Label1.Text += "<td>";
                                Label1.Text += s;
                                Label1.Text += "</td>";
                            }
                            Label1.Text += "</tr>";
                        }
                        Label1.Text += "</table>";
                    }
                }
            }          
        }

        // to override on save
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if ((SPContext.Current.FormContext.FormMode == SPControlMode.New) ||
                (SPContext.Current.FormContext.FormMode == SPControlMode.Edit))
            {
                SPContext.Current.FormContext.OnSaveHandler += myCustomSaveHandler;
            }
        }

        protected void myCustomSaveHandler(object sender, EventArgs e)
        {
            Page.Validate();
            if (Page.IsValid)
            {

                string value = "";
                GridView GridView1 = (GridView)UserControl11.FindControl("GridView1");
                foreach (GridViewRow row in GridView1.Rows)
                {
                    string studentName = ((Label)row.Cells[0].FindControl("Label1")).Text;
                    string studentStatus = ((DropDownList)row.Cells[1].FindControl("DropDownList1")).SelectedValue;
                    value += studentName + "," + studentStatus + "#";
                }
                ItemFieldValue = value;
                SPContext.Current.ListItem.Update();
            }

        }
      
       
    }
}
7.    Back to Attendance class and override the "FieldRenderingControl” of our field.
public override BaseFieldControl FieldRenderingControl
        {
            get
            {
                BaseFieldControl fieldControl = new AttendanceCustomFieldRendering();
                fieldControl.FieldName = InternalName;
                return fieldControl;
            }
        }
8.    Till this step you can customize the edit, display and new form for this field type but you can't do this in view. If you want to do this follow the next steps:
9.    Map the xsl folder, this one is in the folder "SharePointRoot\template\layouts".
10.  Then add an xsl file. xsl file named the same as the xml file of our field. It should be called "fldtypes_AttendanceFieldType.xsl".
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" />
  <xsl:template match="FieldRef[@FieldType='Attendance']" mode="Text_body">
    <xsl:param name="thisNode" select="."/>   
    <table style="border: 1px solid black;width:200px;">
      <tr>
        <td><b>Name</b></td>
        <td><b>Status</b></td>
      </tr>
      <xsl:call-template name="tokenize">
        <xsl:with-param name="AttendanceValue" select="$thisNode/@*[name()=current()/@Name]"/>
      </xsl:call-template>
    </table>
  </xsl:template>
  <xsl:template name="tokenize">
    <xsl:param name="AttendanceValue"/>       
    <xsl:choose>
      <xsl:when test="not(contains($AttendanceValue, '#'))"></xsl:when>
      <xsl:otherwise>
        <tr>
          <td>
            <xsl:variable name="tt" select="normalize-space(substring-before($AttendanceValue, ','))"/>
            <xsl:value-of select="$tt"/>
          </td>
          <td>
            <xsl:variable name="tt1" select="normalize-space(substring-before($AttendanceValue, '#'))"/>
            <xsl:variable name="tt2">
              <xsl:value-of select="normalize-space(substring-after($tt1, ','))"/>
            </xsl:variable>
            <xsl:value-of select="$tt2"/>
          </td>
        </tr>
        <xsl:call-template name="tokenize">
          <xsl:with-param name="AttendanceValue" select="substring-after($AttendanceValue, '#')"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Snapshot from the final solution:

Snapshot from SharePoint server:
New Item Form
Display Form
Edit Form

View Form

4 comments

Interesting post!, ¿Could you please share your code? there are some doubts with code of the second method (server) vs images shown at the end. Thanks so much!

Reply

Good blog, thanks for sharing useful information.
Click More Details Visit Our Website

Texus
Texus Systems

Reply


Thanks for sharing your valuable information.I found it very useful.Keep posting amazing content like this.

Legacy Modernization from Integritas Solutions

Reply
This comment has been removed by the author.

Post a Comment