Create a jqueryui sortable Sharepoint list with CEWP

Sep 22, 2011 at 11:13 PM

Been after a solution for this for a while now, here's what I came up with, figured others might have some ideas for improvements or at least find the code useful.

This code allows you to create a CEWP that contains an unordered list from Sharepoint list items, and attaches the sortable behavior to it, so that when an item is moved up or down the list, it is saved back to the Sharepoint list with a "Priority" value representing its order in the list.

It's a rudimentary solution at this point, but got me what I needed for now...enjoy!

Set "targetListName" to the name of the list you want to be able to sort
Add an integer column to the target list called "Priority"

<link rel="stylesheet" type="text/css" href="http://spsite/js/css/ui-lightness/jquery-ui-1.8.16.custom.css"/>
<script language="javascript" type="text/javascript" src="http://spsite/js/jquery-1.6.4.min.js"></script>
<script language="javascript" type="text/javascript" src="http://spsite/js/jquery-ui-1.8.16.custom.min.js"></script>
<script language="javascript" type="text/javascript" src="http://spsite/js/jquery.SPServices-0.6.2.min.js"></script>

<script language="javascript" type="text/javascript">

//CONFIGURATION VARIABLES
//Assumes that this list is on the same site as the WebPart
var targetListName = "PrioritizedList";

function loadPrioritizedList() {
$("#tasksUL").empty();
$().SPServices({
    operation: "GetListItems",
    async: false,
    listName: targetListName,
    CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='ID' />><FieldRef Name='Priority' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName='z:row']").each(function() {
        var liHtml = "<li id=" + $(this).attr("ows_ID") + " class='ui-state-default'><span class='ui-icon ui-icon-arrowthick-2-n-s'></span>" + parseInt($(this).attr("ows_Priority")) + ' ' + $(this).attr("ows_Title") + "</li>";
        $("#tasksUL").append(liHtml);
      });
    }
  });
}

function saveListOrder() {

//alert('Beginning to save items...');

$("#saveLink").text(">> Saving list order....");

var numItems = $('#tasksUL li').size();

$('#tasksUL li').each(function(index) {
    
    var itemId = $(this).attr("id");
    var rank = index + 1;
    itemId = itemId + '';
    rank = rank + '';
    //alert(rank + ': ' + itemId + " : " + $(this).text());
    saveItemRank(itemId + '', rank);
    //$( "#progressbar" ).progressbar({value: (rank/numItems)*100});
  });
loadPrioritizedList();
$("#saveLink").text("Save List Order");
}

function saveItemRank(itemId, rank)
{
  $().SPServices({
    operation: "UpdateListItems",
    debug:true,
    async: false,
    batchCmd: "Update",
    listName: targetListName,
    ID: itemId,
    valuepairs: [["Priority", rank]],
    completefunc: function(xData, Status) {
            //alert(xData.responseXML.xml);
          }
      });
}

</script>

<style>
	#tasksUL { list-style-type: none; margin: 0; padding: 0;  }
	#tasksUL li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; cursor: pointer;}
	#tasksUL li span { position: absolute; margin-left: -1.3em; }
#progressbar { list-style-type: none; margin: 0; padding: 0; width: 60%; }
	</style>

<script type="text/javascript">
 
$(document).ready(function(){
 $("#msgid").html("Drag list items to save priority.");
 loadPrioritizedList();
 $( "#progressbar" ).progressbar({value: 0}).hide();
 $("#tasksUL").sortable({
   update: function(event, ui) { saveListOrder();
  }
 });
});
 
</script>
 
<div id="msgid">
</div>
<br>
<!--
<a href="#" id="saveLink" onclick="saveListOrder();">Save List Order</a>
<br>
-->
<div id="progressbar" class="ui-progressbar ui-widget ui-widget-content ui-corner-all"><!-- --></div>
<br>
<ul id="tasksUL"/>

Nov 16, 2011 at 1:43 PM

i found this after inspiration from Marc D Anderson's presentantion at the last Sharepoint Saturday in Nottingham.

your code a great help, here's how i got it to reflect the new changes instantly by

1) use the CAMLQuery parameter the spservices GetListItems operation

2) tweaking the sort

<link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/ui-lightness/jquery-ui-1.8.16.custom.css"/>
<script language="javascript" type="text/javascript" src="/_layouts/1033/jquery-1.6.4.min.js"></script>
<script language="javascript" type="text/javascript" src="/_layouts/1033/jquery-ui-1.8.16.custom.min.js"></script>
<script language="javascript" type="text/javascript" src="/_layouts/1033/jquery.SPServices-0.6.2.min.js"></script>

<script language="javascript" type="text/javascript">
var targetListName = "Manager";

function loadPrioritizedList() {

$("#tasksUL").empty();
$().SPServices({
    operation: "GetListItems",
    async: false,
    listName: targetListName,
    CAMLViewFields: "<ViewFields><FieldRef Name='ManagerLanId' /><FieldRef Name='ID' /></ViewFields>",
    CAMLQuery: '<Query>' +
        '<OrderBy>' +
            '<FieldRef Name="Priority" />' +
        '</OrderBy>' +
        '</Query>',
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName='z:row']").each(function() {
        var liHtml = "<li id=" + $(this).attr("ows_ID") + " class='ui-state-default' priorityId=" + $(this).attr("ows_Priority") + "><span class='ui-icon ui-icon-arrowthick-2-n-s'></span>" + $(this).attr("ows_ManagerLanId") + "</li>";
        $("#tasksUL").append(liHtml);
      });
    }
  });

 // debugger;
    var elems = $('#tasksUL').children('li').remove();
    elems.sort(function(a,b){
        //return parseInt(a.id) > parseInt(b.id);
        return parseInt(a.attributes['priorityId']) > parseInt(a.attributes['priorityId']);       
    });
    $('#tasksUL').append(elems);


}

//Beginning to save items
function saveListOrder() {
    $("#saveLink").text(">> Saving list order....");

    var numItems = $('#tasksUL li').size();

    $('#tasksUL li').each(function(index) {
   
        var itemId = $(this).attr("id");
        var rank = index + 1;
        itemId = itemId + '';
        rank = rank + '';   
        //debugger;
        //alert('rank:' + rank + ': itemId: ' + itemId + " : " + $(this).text());
        saveItemRank(itemId + '', rank);
        $( "#progressbar" ).progressbar({value: (rank/numItems)*100});
    });

    //loadPrioritizedList();
    $("#saveLink").text("Save List Order");
}



function saveItemRank(itemId, rank)

  $( "#progressbar" ).progressbar({value: 0}).show();
  $().SPServices({
    operation: "UpdateListItems",
    debug:true,
    async: false,
    batchCmd: "Update",
    listName: targetListName,
    ID: itemId,
    valuepairs: [["Priority", rank]],
    completefunc: function(xData, Status) {
            //alert(xData.responseXML.xml);
    }
  });
}

</script>

<style>
    #tasksUL { list-style-type: none; margin: 0; padding: 0;  }
    #tasksUL li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; cursor: pointer;}
    #tasksUL li span { position: absolute; margin-left: -1.3em; }
    #progressbar { list-style-type: none; margin: 0; padding: 0; width: 60%; }
</style>

<script type="text/javascript">
 
$(document).ready(function(){
    $("#msgid").html("Drag list items to save priority.");
    loadPrioritizedList();
    $( "#progressbar" ).progressbar({value: 0}).hide();
    $("#tasksUL").sortable({
        update: function(event, ui) {
            saveListOrder();
        }
   
    });
});
 
</script>
 
<div id="msgid">
</div>
<br>
<a href="#" id="saveLink" onclick="saveListOrder();">Save List Order</a>
<br>
<div id="progressbar" class="ui-progressbar ui-widget ui-widget-content ui-corner-all"></div>
<br>
<ul id="tasksUL"/>

Apr 13, 2012 at 3:52 PM

i had to pi had to produce another version of this.  i found that the more recent javascript libraries, this approach wont work.  the looping on z:row nodes needs to be amended.

heres the code

<link rel="stylesheet" type="text/css" href="http://oneweb/sites/IS/Customerexperience/Intranet/SiteAssets/scripts/jquery-ui-1.8.18.custom/css/smoothness/jquery-ui-1.8.18.custom.css"/>
<script language="javascript" type="text/javascript" src="http://oneweb/sites/IS/Customerexperience/Intranet/SiteAssets/scripts/jquery-ui-1.8.18.custom/js/jquery-1.7.1.min.js"></script>
<script language="javascript" type="text/javascript" src="http://oneweb/sites/IS/Customerexperience/Intranet/SiteAssets/scripts/jquery-ui-1.8.18.custom/js/jquery-ui-1.8.18.custom.min.js"></script>
<script language="javascript" type="text/javascript" src="http://oneweb/sites/IS/Customerexperience/Intranet/SiteAssets/scripts/jquery.SPServices-0.6.2.min.js"></script>
<script language="javascript" type="text/javascript">

//CONFIGURATION VARIABLES
//Assumes that this list is on the same site as the WebPart
var targetListName = "Team Priorities";

function loadPrioritizedList() {

$("#tasksUL").empty();

$().SPServices({
    operation: "GetListItems",   
    webURL: "http://oneweb/sites/IS/Customerexperience/Intranet/intmgmt",
    listName: targetListName,
    CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='Priority' /></ViewFields>",
 CAMLQuery: '<Query>' +
  '<OrderBy>' +
   '<FieldRef Name="Priority" />' +
  '</OrderBy>' +
  '</Query>',   
    completefunc: function (xData, Status) {
      //$(xData.responseXML).find("[nodeName='z:row']").each(function() {  //this doesnt work in the latest jquery, it was a bug that it did so
 $(xData.responseXML).find("z\\:row,row").each(function() {
  var liHtml = "<li id=" + $(this).attr("ows_ID") + " class='ui-state-default' priorityId=" + $(this).attr("ows_Priority") + "><span class='ui-icon ui-icon-arrowthick-2-n-s'></span>" + $(this).attr("ows_Title") + "</li>";
        $("#tasksUL").append(liHtml);

      });
    }
  });


    var elems = $('#tasksUL').children('li').remove();
    elems.sort(function(a,b){
 return parseInt(a.attributes['priorityId']) > parseInt(a.attributes['priorityId']);  
    });
    $('#tasksUL').append(elems);


}

//Beginning to save items
function saveListOrder() {
 $("#saveLink").text(">> Saving list order....");

 var numItems = $('#tasksUL li').size();

 $('#tasksUL li').each(function(index) {
   
  var itemId = $(this).attr("id");
  var rank = index + 1;
  itemId = itemId + '';
  rank = rank + '';   

  saveItemRank(itemId + '', rank);
  $( "#progressbar" ).progressbar({value: (rank/numItems)*100});
 });

 //loadPrioritizedList();
 $("#saveLink").text("Save List Order");
}

 

function saveItemRank(itemId, rank)

  $( "#progressbar" ).progressbar({value: 0}).show();
  $().SPServices({
    operation: "UpdateListItems",
    debug:true,
    async: false,
    batchCmd: "Update",
    listName: targetListName,
    ID: itemId,
    valuepairs: [["Priority", rank]],
    completefunc: function(xData, Status) {
            //alert(xData.responseXML.xml);
    }
  });
}

</script>

<style>
 #tasksUL { list-style-type: none; margin: 0; padding: 0;  }
 #tasksUL li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; cursor: pointer;}
 #tasksUL li span { position: absolute; margin-left: -1.3em; }
 #progressbar { list-style-type: none; margin: 0; padding: 0; width: 60%; }
</style>

<script type="text/javascript">
 
$(document).ready(function(){
 $("#msgid").html("Drag list items to save priority.");
 loadPrioritizedList();
 $( "#progressbar" ).progressbar({value: 0}).hide();
 $("#tasksUL").sortable({
  update: function(event, ui) {
   saveListOrder();
  }
 
 });
});
 
</script>
 
<div id="msgid">
</div>
<br>
<a href="#" id="saveLink" onclick="saveListOrder();">Save List Order</a>
<br>
<div id="progressbar" class="ui-progressbar ui-widget ui-widget-content ui-corner-all"></div>
<br>
<ul id="tasksUL"/>

 

Coordinator
Apr 13, 2012 at 4:49 PM

Note that there's now a function in SPServices called SPFilterNode. Using it ought to help future-proof your code, as I'll try to keep it working when jQuery changes.

M.

Aug 10, 2012 at 8:56 PM

Thank you for sharing! Works great! So much better than having to re-number the Priority values manually. Makes me wonder why I waited so long to use SPServices.

Here's one thing that may help someone else who is just starting out with jQuery and SPServices...Not only do you need to download these libraries, but the code above also takes advantage of jQuery UI, which is another library to download. That's the piece I was missing, and it took me a day to spot this. Once I compared my code to this code, I realized I was missing "/jquery-ui-1.8.16.custom.css" and "/jquery-ui-1.8.16.custom.min.js".

Fine work, gentlemen!

Jan 17, 2013 at 10:04 PM

I have been looking all over the internet for a solution to my priority re-ordering problem in sharepoint. I think this is exactly what I need, but I believe my inexperience in code/SharePoint is getting the best of me. I am trying to implement the code, but I am not exactly sure what I need to change in the "$(xData.responseXML).find("z\\:row,row").each(function() {" line. What specifically do I need to reference in place of z:row?

Coordinator
Jan 18, 2013 at 1:17 AM

The jQuery team changed something in the library so that .find("z\\:row,row") no longer works. I think it was in 1.7 or so.

Instead, use the SPFilterNode function in SPServices: .SPFilterNode("z:row"). I put that into SPServices to [hopefully] future-proof us in case there are more changes in jQuery

M.

Jan 23, 2013 at 9:57 PM

Thanks for the help! It is working great in Chrome (it is exactly what I was looking for), but I am unable to get it running in IE (was running IE8 and an upgrade to IE9 didn't fix it). It won't show the data on the screen. What browser were you running and should it make a difference? Until I can figure out a solution, I will just continue to use Chrome.

Jan 24, 2013 at 2:42 AM

I recently used jquery ui sortable and found that the issues i was experiencing where all caused by the page doctype (set by the master page). I had to change it.

Paul

Sent from mobile

Jan 24, 2013 at 4:18 AM

I just found the problem. For some reason IE was not able to reference one of the jquery files on the SharePoint (despite the correct reference with Chrome). I redirected to the jquery site and everything now works on all browsers.

Coordinator
Jan 24, 2013 at 2:28 PM

Paul:

I've used jQueryUI .sortable() with no problems in the past. I have never had to change the doctype for anything I've done with jQuery.

M.

Jan 24, 2013 at 3:42 PM
I was working with sp2007 and I'm bit sure if this is an issue with sp or my company, but all sites I have created here, none even set a doctype. I found some weird stuff with layout (CSS) and jumpy behaviors.

_____
Paul

Sent from mobile device.