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 +
"'
> </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!
ReplyGood blog, thanks for sharing useful information.
ReplyClick More Details Visit Our Website
Texus
Texus Systems
Thanks for sharing your valuable information.I found it very useful.Keep posting amazing content like this.
Legacy Modernization from Integritas Solutions
Post a Comment