Delete a ListItem from SharePoint ListView WebPart [XSLT]

The objective here is to delete a single or multiple ListItems from a single SharePoint List using a ListView WebPart i.e., to delete a ListItem from client side. In order to achieve this, we will be making an ajax call to the SharePoint WebService, Lists.asmx. SharePoint provides a number of WebServices with various functionalities. One of them is Lists.asmx. This service has many apis related with SharePoint List. We’re gonna call UpdateListItems api with the Delete command to delete a single or multiple ListItems accordingly. The url of this service is kept relative as, ../_vti_bin/lists.asmx.Following is the schema of this api.

POST /_vti_bin/Lists.asmx HTTP/1.1
Host: win-hk4iec2ge2r
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://schemas.microsoft.com/sharepoint/soap/UpdateListItems"

<?xml version="1.0" encoding="utf-8"?>
 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
 <UpdateListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
 <listName>string</listName>
 <updates>string</updates>
 </UpdateListItems>
 </soap:Body>
</soap:Envelope>

The approach is going to be pretty simple. We’ll be editing our custom XSLT as a normal HTML file with an exception of encoding the HTML schema of the api as we can not use any html tag inside an xml declaration. First we’ll define our HTML structure in the XSLT. Here, we will generate an HTML checkBox against the Title of all the items displayed. The IDs of these checkBoxes are the SharePoint ID of the corresponding ListItem they represent. This will help us to get the IDs of the ListItem that User wants to delete.



<table style="width:100%; padding-left: 0px">

<tr>

<td colspan="2" style="text-align: left; width: 40%"> 
 <input id="chkSelectAll" type="checkbox" name="checkbox" onclick="OnChangeCheckbox(this)" value="SelectAll" />
 <label id="SelectAll">Select All</label>
 </td>


<td style="text-align: left;">
 <button type="button" onclick="DeleteItems()" class="buttonv">Delete</button>
 </td>

 </tr>

</table>

Next declare the checkbox where the code for, for-each rows are written. As mentioned, the checkBoxes will appear against the title for each item in the view.


<div>


 <input type="checkbox" name="checkbox" value="{@ID}" id="{@ID}" onclick="ClearParent(this)"/>
 <a class="list_link" title="{@ListId_x003a_Title}" href="viewList.aspx?ListId={@ListId_x003a_ID}">
 <xsl:value-of select="@ListId_x003a_Title" disable-output-escaping="yes" />
 </a>
 
 <span class="submittedby"></span>
 
 <span class="summary">
 <xsl:value-of select="@ListId_x003a_ShortSummary" disable-output-escaping="yes" />
 </span>
 

</div>

Now all the JavaScript required to complete this operation.

        
        //This function gets the ID of all the ListItems that the user has selected and mark them for Deletion.
        function GetItemsToBeRemoved(){
          var counter = 0;
          var checkedIds = new Array();
          var cbs = document.getElementsByTagName('input');
          for(var i=0; i < cbs.length; i++) {               if(cbs[i].type == 'checkbox') {                   if(cbs[i].value != "SelectAll"){                       if(cbs[i].checked){                         checkedIds[counter++] = cbs[i].id;                       }                   }               }           }           return checkedIds;         }         //This is the function which is called on the Delete Button Click event. Only "" without encoding.         function DeleteItems(){           var checkedIds = GetItemsToBeRemoved();           if(checkedIds.length > 0){
            GenerateRequest(checkedIds);
          }
          else{
            alert('Plz select atleast 1 item to delete.');
          }
        }
        
        //Create and send the SOAP request. Again HTML tags are encoded. Since we'll be generating a Batch request for deletion, we have to generate this request in a for-loop.
        function GenerateRequest(checkedIds){

            var soapEnv = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><UpdateListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'><listName>SpListName</listName><updates><Batch>";
            var methodEnv1 = "<Method ID='1' Cmd='Delete'><Field Name='ID'>";
            var methodEnv2 = "</Field></Method>";
            var soapEnv2 = "</Batch></updates></UpdateListItems></soap:Body></soap:Envelope>";

 
            //Foreach selected item, create a delete request. 
            for (var i = 0; i < checkedIds.length; i++){
                soapEnv+=methodEnv1 + checkedIds[i] + methodEnv2;
            };

            soapEnv+=soapEnv2;

            //Finally send a single batch request for multiple items. 
            $.ajax({
                    url: "../_vti_bin/lists.asmx",
                    beforeSend: function(xhr) { xhr.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/UpdateListItems");
                },
                type: "POST",
                dataType: "xml",
                data: soapEnv,
                complete: CheckForErrors,
                contentType: "text/xml; charset=\"utf-8\""
            });
        }

        //This function checks if any error has been encountered or not. If no error is found, then it re-Loads the current page to refresh the View.
        function CheckForErrors(xData, status) {

            //alert("Update Status : " + status );
            //alert("Update Status : " + xData.responseText );

            if(status == "success"){
                location.reload(true);
            }

        }

        //helper functions
        
        //Disable the delete button if there are no items to be displayed i.e., the SharePoint List is empty. Call this function on document.ready.
        function ValidateNoRecords(){
            var isDataFound = false;
            var cbs = document.getElementsByTagName('input');
            for(var i=0; i < cbs.length; i++) {
                if(cbs[i].type == 'checkbox') {
                    if(cbs[i].value != "SelectAll"){
                        isDataFound = true;
                        break;
                    }
                }
            }

            if(!isDataFound){
                var id = "#chkSelectAll";
                $(id).closest('tr').hide()
            }

        }

        //Checks whether to display the Delete button or not.
        $(document).ready(function(){
            ValidateNoRecords();
        })

***

Update Exclusive properties[AllowMultiResponses & ShowUser] of a Survey List for SharePoint using service and CSOM C#

Survey List for SharePoint is like any other List except that its got some exclusive properties:

  • ShowUser – Indicates whether to display the user’s name along side its response. Default value is True.
  • AllowMultiResponses – Indicates whether an user can post multiple response for a Survey. Default value is False.

Now usually to update other common properties of a List, like Title, etc., we can easily rely on CSOM. However, there’s no such provision for these two properties or any other exclusive properties of any other List. Here, we’ll be focussing on the Survey List only.So when the Client Object Model fails, turn to services. The service Lists.asmx, comprises of many methods related to Lists. One of the method is UpdateList. This method has the following definition:

[SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/UpdateList", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/", Use=SoapBindingUse.Literal, ParameterStyle=SoapParameterStyle.Wrapped)] 
public XmlNode UpdateList (
    string listName,
    XmlNode listProperties,
    XmlNode newFields,
    XmlNode updateFields,
    XmlNode deleteFields,
    string listVersion
)

The XmlNode parameter listProperties, is the one I’ll be focusing at. This will be in the format of a

XmlNode where we can update/modify the following properties:
AllowMultiResponses TRUE to allow multiple responses to the survey.
Description A string that contains the description for the list.
Direction A string that contains LTR if the reading order is left-to-right, RTL if it is right-to-left, or None.
EnableAssignedToEmail TRUE to enable assigned-to e-mail for the issues list.
EnableAttachments TRUE to enable attachments to items in the list. Does not apply to document libraries.
EnableModeration TRUE to enable Content Approval for the list.
EnableVersioning TRUE to enable versioning for the list.
Hidden TRUE to hide the list so that it does not appear on the Documents and Lists page, Quick Launch bar, Modify Site Content page, or Add Column page as an option for lookup fields.
MultipleDataList TRUE to specify that the list in a Meeting Workspace site contains data for multiple meeting instances within the site.
Ordered TRUE to specify that the option to allow users to reorder items in the list is available on the Edit View page for the list.
ShowUser TRUE to specify that names of users are shown in the results of the survey.
Title A string that contains the title of the list.

As you can see the two exclusive properties of the List Survey, ShowUser & AllowMultiResponses are present here which is exactly what we need. The other properties can also be updated using the CSOM so I won’t be using them here.

One important thing, this method simultaneously, also creates, updates, & deletes Fields/SiteColumns for the given List. However, if you don’t want to use them (as will be the case here) you can pass an empty string as parameters.

Following is the code sample to accomplish this task. The first part demonstrates how to construct the parameter, listProperties.

Desired Format
<List Title=”List_Name” Description=”List_Description” Direction=”LTR”/>

XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode ndProperties = xmlDoc.CreateNode(XmlNodeType.Element, "List", "");
XmlAttribute ndTitleAttrib = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, "Title", "");
XmlAttribute ndDescriptionAttrib = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, "Description", "");
XmlAttribute ndDirectionAttrib = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, "Direction", "");
XmlAttribute ndMultiresponse = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, "AllowMultiResponses", "");
XmlAttribute ndShowUser = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, "ShowUser", "");

ndTitleAttrib.Value = "My Survey";
ndDescriptionAttrib.Value = "Allowing multiple responses for this Survey";
ndDirectionAttrib.Value = "LTR";
ndMultiresponse.Value = "TRUE";
ndShowUser.Value = "TRUE";

ndProperties.Attributes.Append(ndTitleAttrib);
ndProperties.Attributes.Append(ndDescriptionAttrib);
ndProperties.Attributes.Append(ndDirectionAttrib);
ndProperties.Attributes.Append(ndMultiresponse);
ndProperties.Attributes.Append(ndShowUser);

So basically we're creating the following node

<
List Title="My Survey" Description="Allowing multiple responses for this Survey" Direction="LTR" AllowMultiResponses="TRUE" ShowUser="TRUE"/>

Finally, we’re going to use this parameter in the UpdateList method. The following code is a sample demonstration to call this method from the Lists.asmx service. Note that since this service is dependant on the site’s url, it will always vary from site to site. Hence we’re setting the url of the web service at runtime. One more thing, all the parameters that will be passed should be string i.e., the OuterXml property for XmlNode parameters.

string webServiceUrl = ctx.Web.Url + "/_vti_bin/Lists.asmx";

StringBuilder sbEnvelope = new StringBuilder();
sbEnvelope.Append("");
sbEnvelope.Append("");
sbEnvelope.Append(String.Format(
    "" +
        "" +
            "{0}" +
            "{1}" +
            "{2}" +
            "{3}" +
            "{4}" +
            "{5}" +
        "" +
    ""
    , id, ndProperties.OuterXml, String.Empty, String.Empty, String.Empty, version));
sbEnvelope.Append("");

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(webServiceUrl);
req.Method = "POST";
req.ContentType = "text/xml; charset=\"utf-8\"";
req.Accept = "text/xml";
req.Headers.Add("SOAPAction", "\"http://schemas.microsoft.com/sharepoint/soap/UpdateList\"");
req.UserAgent = "FrontPage";
req.UseDefaultCredentials = false;

Uri targetSite = new Uri(ctx.Web.Url);
SharePointOnlineCredentials spCredentials = (SharePointOnlineCredentials)ctx.Credentials;
string authCookieValue = spCredentials.GetAuthenticationCookie(targetSite);
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(
    new Cookie("FedAuth",
        authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),
        String.Empty,
        targetSite.Authority));

using (IO.Stream stream = req.GetRequestStream())
{
    using (IO.StreamWriter writer = new IO.StreamWriter(stream))
    {
        writer.Write(sbEnvelope.ToString());
    }
}

WebResponse response = req.GetResponse();
using (IO.Stream responseStream = response.GetResponseStream())
{
    XmlDocument xDoc = new XmlDocument ();
    xDoc.Load(responseStream);

    if (xDoc.DocumentElement != null && xDoc.DocumentElement.InnerText.Length > 0)
    {
        Debug.WriteLine(String.Concat(DateTime.Now.ToShortTimeString(), " Response of the Survey List Update: ", xDoc.DocumentElement.InnerText));
    }
}

Here’s a screen-shot of the UpdateList method. You can view your site’s service at your site’s url + “_vti_bin/Lists.asmx”