SharePoint, in addition to storing documents, allows you to store data in the form of “Lists” and offers various ways to interact with your data once it’s there. Standard SharePoint forms, InfoPath forms, the Data Sheet view, querying with Excel or Access, Office plugins and desktop applications using web services all have their place and each have their pros and cons. Often, the first challenge in a SharePoint development project is deciding which method best serves all of the people involved, from the development team through the site administrators and content managers to the “End Users” or content consumers. No one has ever complained that SharePoint was too easy to use.
Consider the scenario of a project list with a choice column indicating the stage of each project. Our end user, on a regular basis, needs to update the value of this column on many or all of the items in the list. Yes they could open each item one at a time and edit the stage of the project or use the datasheet view to edit multiple rows. But where’s the fun in that? We want to drag things and then drop them! Let’s find out how easy it is.
You may have seen other ways to Beautify SharePoint with ChartJS or JSLink. Here's another great way to improve the SharePoint UI.
Get your SharePoint list ready
First make sure that your list has a choice column that you want to classify each item by. I called mine ”ColumnType”.
Make sure that “Allow Fill-In choices” is not selected.
This can be a “site column” if you wish, but for the purposes of this exercise do not use a lookup or managed metadata column.
Create a new view
Next make a new view. Be sure to include your choice column.
Feel free to add any filters that may be required.
Make sure to show plenty of records and do not use paging.
Now save your view and put some data in your list.
Open your view in SharePoint Designer
We will need to reference some JavaScript Libraries in the PlaceHolderAdditionalPageHead content area.
jQuery, jQueryUI and SPServices
<asp:content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:RssLink runat="server"/>
<script type="text/javascript" src="/path/to/your/JavaScript/library/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/path/to/your/JavaScript/library/jquery-ui-1.10.3.custom.min.js"></script>
<script type="text/javascript" src="/path/to/your/JavaScript/library/jquery.SPServices-2013.01.min.js"></script>
</asp:content>
Next we need to modify the ListViewWebPart.
Look for JSLink and XslLink in the XmlDefinition of your WebPart code.
We won’t be needing them any more so delete them. If you choose to preview your view in a browser at this point you will get an error. Don’t worry, all will be made right soon.
Create a new StyleSheet
Now, after the closing XmlDefinition tag add the following:
<Xsl>
<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:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="dvt_apos">'</xsl:param>
<xsl:param name="ManualRefresh"></xsl:param>
<xsl:variable name="dvt_1_automode">0</xsl:variable>
<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<xsl:call-template name="dvt_1"/>
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">RepForm3</xsl:variable>
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
<xsl:variable name="RowLimit" select="300" />
<div id="colWrapper">
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
</div>
<div id="output"></div>
</xsl:template>
<xsl:template name="dvt_1.body">
<xsl:param name="Rows" />
</xsl:template>
</xsl:stylesheet>
</Xsl>
This is the basic framework for the WebPart.
Add the following after the dvt_1.body template
<xsl:template name="dvt_1.column">
<xsl:param name="Rows" />
<xsl:param name="ColumnType" />
<xsl:param name="className" />
<xsl:variable name="data" select="translate($ColumnType,' ','|')"/>
<xsl:variable name="newline"><xsl:text> </xsl:text></xsl:variable
<div class="actionColumn" id="{$className}" data="{$ColumnType}">
<h3><xsl:value-of select="$ColumnType" /></h3>
<xsl:for-each select="$Rows[@ColumnType = $ColumnType]">
<ul class="contact-item {$className}" id="contactitem_{@ID}">
<li class="company" ><xsl:value-of select="@Title" /></li>
<li class="titlecontent" title="{@Title}{$newline}{@Details}"><xsl:value-of select="$ColumnType" /></li>
<li><xsl:value-of select="@Details"/></li>
<li class="author">~<xsl:value-of select="@Author.title" /></li>
</ul>
</xsl:for-each>
</div>
</xsl:template>
This will display list items filtered by our choice column.
Now let’s call our template from the dvt_1.body template - once for each choice.
<xsl:template name="dvt_1.body">
<xsl:param name="Rows" />
<xsl:call-template name="dvt_1.column">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="ColumnType">Type 1</xsl:with-param>
<xsl:with-param name="className">phone</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="dvt_1.column">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="ColumnType">Type B</xsl:with-param>
<xsl:with-param name="className">meeting</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="dvt_1.column">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="ColumnType">Type Three</xsl:with-param>
<xsl:with-param name="className">email</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="dvt_1.column">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="ColumnType">Type IV</xsl:with-param>
<xsl:with-param name="className">proposal</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="dvt_1.column">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="ColumnType">Other</xsl:with-param>
<xsl:with-param name="className">other</xsl:with-param>
</xsl:call-template>
</xsl:template>
Let’s make it look nice
Add the following styles to the PlaceHolderAdditionalPageHead. Of course, in the real world you would link to a CSS stylesheet.
<style type="text/css" >
.s4-title {display:none;}
#showRibbon {
float:right;position:absolute;right:3px; top:3px;
cursor:pointer; border-bottom:1px solid #333;border-left:1px solid #333;
width:150px;text-align:center; padding:2px 10px;
}
#colWrapper { width:100%;margin:0 auto; text-align:center}
.actionColumn {
width:216px;
display:inline-block;
padding:20px;
min-height:100%;
text-align:left;
}
.actionColumn h3{
text-align:center;
border-bottom:2px solid #333;
padding-bottom:3px;
width:222px;
}
.contact-item {
list-style:none;
cursor:pointer;
width:200px;
height:80px;
padding:10px 10px 20px 10px ;
margin:0 0 10px 0;
border:1px solid #666;
position:relative;
overflow:hidden;
color:#555;
}
.contact-item-highlight {
width:200px;
height:80px;
padding:10px 10px 20px 10px ;
margin:0 0 10px 0;
border:1px solid #dd7;
background-color:#FFFFAA!important;
}
.actionColumn:first-child ul { float:left; margin-right:9px;}
.actionColumn:first-child ul.contact-item-highlight { float:left; }
.contact-item li:first-child{
font-weight:bold;
border-bottom:1px solid #333;
padding-bottom:5px;
margin-bottom:5px;
color:#000;
}
#phone ul{ background-color:#8EC840}
#meeting ul { background-color:#F8CD4E;}
#email ul { background-color:#7BABDF}
#proposal ul {background-color:#FF9A35}
#other ul { background-color:#FF7171}
.titlecontent {
overflow:hidden; height:20pt;
width:auto; line-height:10pt; margin:5pt 0 0 5pt;
color:#000; font-size:9pt; font-style:italic; padding-left:2pt;text-indent:-2pt;
}
.author {
text-align:right; text-transform:capitalize;
position:absolute; bottom:5px; right:5px;
}
#output {
position:absolute;display:none;z-index:10000;
width: 250px; height:100px;
text-align:center; ;line-height:75px;
border:1px solid #ccc; background-color:#fff; border-top-width:25px;
}
</style>
Let’s make it do something.
Add the following to PlaceHolderAdditionalPageHead
<script type="text/javascript">
$(document).ready(function($) {
$('.contact-item').click(function(e){return false;})
$('.contact-item').bind("contextmenu",function(e){return false;});
$("#phone,#meeting,#email,#proposal,#other").sortable({
connectWith: ".actionColumn",
items:"ul",
placeholder: "contact-item-highlight",
receive: function( event, ui ) {
var thisThing = $(event.target)
var data = thisThing.attr('data')
updateListItem(ui.item.attr('id').split('_')[1] ,data , ui.item)
}
}).disableSelection();
var updateListItem = function(item,data,etarg){
position = etarg.position();
$().SPServices({
operation: "UpdateListItems",
batchCmd: "Update",
listName: "DraggableList", //Make sure to use the name of your list
valuepairs: [["ColumnType",data]],
ID: item,
completefunc: function(xData, Status) {
var outputText = 'Item Successfully Updated'
if(Status != 'success'){ outputText = 'There was an error processing your request.'}
$('#output').css({'left':position.left+100,'top':position.top+150})
.text(outputText )
.fadeIn(500)
.delay(2000)
.fadeOut(500);
}
});
}
});
</script>
Start Dragging and Dropping.
Drag an item from one column to another and the “Choice” value is updated asynchronously using SPServices.