Remove Webpart from pages using SharePoint CSOM

Using SharePoint.Client (CSOM) you can easily remove a webpart from a page.
In this case we are looking for a webpart with an specific title, but you could also use another property, like ZoneIndex, Hidden, IsClosed, etc


namespace TheUnderNet.SharePoint
{
    public class PageHelper
    {
        public void RemoveWebpart(SharePoint.Client.Web web, SharePoint.Client.ClientContext clientContext, string webpartTitle)
        {
            try
            {
                clientContext.Load(web, w => w.ServerRelativeUrl);
                clientContext.ExecuteQuery();

                SharePoint.Client.File page = web.GetFileByServerRelativeUrl(web.ServerRelativeUrl + "/Pages/Default.aspx");

                //Later we can check if the page is checked out, and who has it.
                clientContext.Load(page, p => p.CheckedOutByUser, p => p.CheckOutType, p => p.CheckedOutByUser.Email);
                clientContext.ExecuteQuery();

                SharePoint.Client.WebParts.LimitedWebPartManager manager = page.GetLimitedWebPartManager(SharePoint.Client.WebParts.PersonalizationScope.Shared);

                //Load all the webparts and webpart definitions with their titles
                clientContext.Load(manager, m => m.WebParts, m => m.WebParts.Include(x => x.WebPart, y => y.WebPart.Title, z => z.WebPart.Title));
                clientContext.ExecuteQuery();

                SharePoint.Client.WebParts.WebPartDefinition webpartDef = manager.WebParts.Where(x => x.WebPart.Title.ToLower() == webpartTitle.ToLower()).FirstOrDefault();

                if (webpartDef != null)
                {
                    if (page.CheckOutType != CheckOutType.None && !Object.Equals(page.CheckedOutByUser, null))
                    {
                        throw new Exception("Webpart was found but page is checked out by user " + page.CheckedOutByUser.Email);
                    }
                    else
                    {
                        page.CheckOut();
                        webpartDef.DeleteWebPart();
                        clientContext.ExecuteQuery();

                        page.CheckIn("Webpart removed", CheckinType.MajorCheckIn);
                        clientContext.ExecuteQuery();

                        //TODO: Log action was acomplished
                    }
                }
                else
                {
                    throw new Exception("Webpart not found");
                }
            }
            catch (Exception ex)
            {
                //TODO: Handle exception
            }
        }
    }
}

You can also do a loop across many sites and instead of throwing exceptions, you can use a StringBuilder to store the result of each site and then save it to a txt or csv file.

Advertisements

List to List with “Add” and “Remove” buttons using JQuery.

Usually in CRUD operations (or not), we have to handle multiple associations to our main entity. That would be “one-to-many” relationship, and a great way to deal with it is to implement two HTML select with “Add” and “Remove” buttons.
The idea is to move elements from one list to another depending on which button is pressed.

Let’s see what we need in our HTML code.


<select size="5" id="lstFrom">
	<option value="1">Option 1</option>
	<option value="2">Option 2</option>
	<option value="3">Option 3</option>
</select>

<a id="btnAdd" href="#">Add</a>        
<a id="btnRemove" href="#">Remove</a>

<select size="5" id="lstTo">
</select>

For the logic, I use JQuery to make it easier to handle events.


$("#btnAdd").click(function () {

        var text = $('#lstFrom > option:selected').text();
        var val = $('#lstFrom > option:selected').val();

        if (text != '') {

            $("#lstFrom  option[value='" + val + "']").remove();
            $("#lstTo").append("<option value='" + val + "'>" + text + "</option>");
        }
    });

    $("#btnRemove").click(function () {

        var text = $('#lstTo > option:selected').text();
        var val = $('#lstTo > option:selected').val();

        if (text != '') {

            $("#lstTo option[value='" + val + "']").remove();
            $("#lstFrom").append("<option value='" + val + "'>" + text + "</option>");
        }
    });

It’s simple and it has no complexity at all. Basically, it removes content from one side and adds it to the other side using value comparison.

To make this even more usefull, we could add a handler to take the selected items and turn them into a string to be able to submit all selected items.
Suppose we have a form with id=”myForm” and a hidden field with id=”txtSelectedId”


$("#myForm").submit(function (e) {

        $("#txtSelectedId").val("");

        var content = "";

        $('#lstTo > option').each(function (index) {
            content += this.value + ";";
        });

        $("#txtSelectedId").val(content);

        return true; //or this.submit();
    });

Hope you find it usefull. Let me know if you have any suggestions or ideas for it!

Reading a SPFieldUser with JavaScript (SharePoint COM)

I had a requirement to develop a SharePoint 2013 workflow which Initiation Form should read a SharePoint list and a particular field that was a SPFieldUser with “Multi” enabled (allowing multiple entries of users).

Since SharePoint already offers a way to read lists and items using JavaScript with SharePont Client Object Model, I developed a method to get query the list and get the required item.

This is the entire JavaScript code I used:


$(document).ready(function () {

	LoadList();

	$("#lstUsers").on('change', function () {

		LoadItemByID(this.value);
	});
});

function LoadList() {

	var context = new SP.ClientContext.get_current();
	var web = context.get_web();
	var list = web.get_lists().getByTitle('MyCustomList');
	var myquery = new SP.CamlQuery();

	var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'ID\'/>' +
		'<Value Type=\'Number\'></Value></Eq></Where></Query></View>');
	myItems = list.getItems(camlQuery);

	context.load(myItems);
	context.executeQueryAsync(Function.createDelegate(this, this.ListSuccess),
	Function.createDelegate(this, this.ListFailed));
}

function ListSuccess() {

	var nameField = "Title";
	var idField = "ID";
	var firstItemId = -1;

	var listEnumerator = this.myItems.getEnumerator();
	$("#lstItems").append("" + currentItem.get_item(nameField) + "");

	while (listEnumerator.moveNext()) {

		var currentItem = listEnumerator.get_current();
		
		if (firstItemId == -1)
			firstItemId = currentItem.get_item(idField);
	}

	if (firstItemId &gt; -1)
		LoadItemByID(firstItemId);

}

function ListFailed(sender, args) {
	alert("Unable to get the List.");
}

function LoadItemByID(itemId) {

	$('#lstSelectedUsers')
			.find('li')
			.remove()
			.end();

	var context = new SP.ClientContext.get_current();
	var web = context.get_web();
	var list = web.get_lists().getByTitle('MyCustomList');
	var myquery = new SP.CamlQuery();

	var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'ID\'/>' +
		'<Value Type=\'Number\'>' + itemId + '</Value></Eq></Where></Query></View>');
	myItems = list.getItems(camlQuery);

	context.load(myItems);
	context.executeQueryAsync(Function.createDelegate(this, this.ItemSuccess),
	Function.createDelegate(this, this.ItemFailed));
}

function ItemSuccess() {

	var usersField = "UsersListField";
	var listEnumerator = this.myItems.getEnumerator();
	
	while (listEnumerator.moveNext()) {

		var currentItem = listEnumerator.get_current();
		var aps = currentItem.get_item(usersField);

		$.each(aps, function (index) {

			$("#lstSelectedUsers").append("<li>" + $(this)[0].$2d_1 + "</li>");
			gblApprovers = gblApprovers + $(this)[0].$1E_1 + ",";
		});
	}
}

function ItemFailed(sender, args) {
	alert("Unable to get the Users field.");
}

Notice that when I need to iterate through all the users that the field contains, I use the $.each() function of JQuery.
Each iteration has an item ($(this)) that is actually an array of objects where the first item is the object that contains the user properties. I dug into this object properties using the Developer Dashboard and I realized the properties that contained the information I wanted were $2d_1 for the user display name and $1E_1 for the user id.
Since those properties always come with the first element of the iterated item, I use the [0].

Next is the HTML code I used:

<table>
<tr>
            <td>
                List of Users:<br /><select id="lstApprovers"/>
            </td>
            <td>
                <ul style="list-style:none;" id="lstSelectedUsers"></ul>
            </td>
        </tr>
</table>

C# and its tricks (Part 1)

Looking at someone else’s code, we always realize there’s always another way to write what we want to do.
Few reasons come to my mind, like “make it look more professional” or just lazyness.
But the point is: why not knowing them?
This first part of the article will point to those strange pieces of code.

The other “IF” statement
We all know this statement from the beginning:

if(isAccessible)
{
//some code
}
else
{
//some else code
}

Or it’s main variation when we have only one line to run within it.

if(isAccessible)
//some code
else
//some else code

And what happen if we want to use an IF statement using only one line?

isAccessible ? isDenied = false : isDenied = true;

So we have our condition before the ‘?’ character, the “true” code and the “false” code splitted by a ‘:’ character.

Using our own named “USING” statement
Suppose we need to add a really long reference to the usings section.
We can name it and then use it.

using controlsToUse = Microsoft.SharePoint.ApplicationPages.WebControls;

And we use it like:

controlsToUse.AjaxCalendarView myCalendar = new controlsToUse.AjaxCalendarView();

Querying content based on its Content Type

It’s almost always required to show SharePoint content based on the Content Type it implements, like a Page or a List Item.
And as you guess, the best approach would be to build a query to retrieve those items, just specifying the ContentType name or Id.
Here you have an example, I will use SPSiteDataQuery since I’m looking for content all across the Site Collection:

<Where>
   <Eq>
    <FieldRef Name='ContentType' />
    <Value Type='Text'>MyCustomContentType</Value>
   </Eq>
</Where>

Using queryText as the query above


SPSiteDataQuery query = new SPSiteDataQuery();

query.RowLimit = 100;
query.Lists = "<Lists ServerTemplate=\"850\" />"; //850 Page Library
query.Webs = "<Webs Scope=\"SiteCollection\" />";
ViewFields = "<FieldRef Name=\"Title\" />";
query.Query = queryText;

But, what happen if, for instance, we have a not too simple Content Type name that includes a character like ‘&’?.
We should be calling Houston, because SharePoint Query Engine lacks of a query pre-interpreter.
If that’s the case, we have two options:

-Use the ContentTypeId field, instead of ContentType

<Where>
   <Eq>
    <FieldRef Name='ContentTypeId' />
    <Value Type='ContentTypeId'>0x0100DC485599A8AC4F70B22792A20E7E5080</Value>
   </Eq>
</Where>

-Use the ContentType name field and declare it as CDATA, replacing it later by using string.Format

<Where>
   <Eq>
    <FieldRef Name='ContentType' />
    <Value Type='Text'><![CDATA[{0}]]></Value>
   </Eq>
</Where>

In my opinion, the best solution is to use the Content Type Id, and use the Content Type name when it’s really needed.
Choose the one you want to use!

Evaluating a value within the ASPX code

When working with ASPX pages and data source bindings, it is usually needed to perform an evaluation of a value to perform an action, like adding styles or making some control visible.
The most common approach would be to override the OnDatabound event (like ItemDataBound), but there is an easier approach that is writing right into the aspx code.

Suppose we have to hide a few controls within a html DIV depending on a field’s value:

<asp:Repeater id="rptUser" runat="server">
<ItemTemplate>
<div>
<asp:Button ID="btnToHide" runat="server"/>
<asp:TextBpx ID="txtToHide" runat="server"/>
</div>
</ItemTemplate>
</asp:Repeater>

A field called “isRegistered” will be the one we will have to evaluate to show or hide our div.

<div style='<%# string.Format("{0}", bool.Parse(Eval("isRegistered").ToString()) ? string.Empty ? "display: none;") %>' />
<asp:Button ID="btnToHide" runat="server"/>
<asp:TextBpx ID="txtToHide" runat="server"/>
</div>

It’s important to mention that “display: none;” won’t be the same as “visible = false”, since the first one is hidden after rendered, and the second one is not even sent to the client site from the server.

Reading a XML file and its nodes

Using a XML file is particulary useful when we have to store information following a structure of nodes and child nodes. It’s simple and light: it needs no provider, it is built using a structure so the performance when reading is much better than using a txt file, and its size is not relevant.

For handling this kind of file and structure, we are going to use the XmlDocument provided by the System.Xml namespace.

I have a XML file that stores employees profiles. In this example, it is actually not important to set the encoding, but it might be when implementing other kind of code.

<?xml version="1.0" encoding="utf-8" ?>
<Profiles>
  <Profile>
    <Name>Smith</Name>
    <EmployeeId>0001</EmployeeId>
    <Birthdate>01-02-1985</Birthdate>
  </Profile>
  <Profile>
    <Name>O'Connor</Name>
    <EmployeeId>0002</EmployeeId>
    <Birthdate>04-03-1987</Birthdate>
  </Profile>
  <Profile>
    <Name>McAllister</Name>
    <EmployeeId>0003</EmployeeId>
    <Birthdate>11-30-1987</Birthdate>
  </Profile>
  <Profile>
    <Name>Johnson</Name>
    <EmployeeId>0004</EmployeeId>
    <Birthdate>01-02-1982</Birthdate>
  </Profile>
  <Profile>
    <Name>Bond</Name>
    <EmployeeId>0007</EmployeeId>
    <Birthdate>01-02-1978</Birthdate>
  </Profile>
</Profiles>

I also have a class named Profile, which is the model to represent and map the xml Profile structure.
Properties names could not be the same.

internal class Profile
    {
        private string name;
        private int employeeId;
        private DateTime birthdate;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        
        public int EmployeeId
        {
            get { return employeeId; }
            set { employeeId = value; }
        }

        public DateTime Birthdate
        {
            get { return birthdate; }
            set { birthdate = value; }
        }
    }

For reading the XML file, I have created the following static class which I called XMLHelper

    internal static class XMLHelper
    {
        public static List<Profile> GetProfiles()
        {
            //Generic List to hold the gathered profiles.
            List<Profile> profilesList = new List<Profile>();

            //Create a XmlDocument that will represent the root Xml file in memory.
            XmlDocument doc = new XmlDocument();
            //We make the XmlDocument load the Xml file. Remember the escape characters.
            doc.Load("c:\\Profiles.xml");

            //NodeList that represents the array of "Profiles" tags. (there is only one though)
            XmlNodeList root = doc.GetElementsByTagName("Profiles");

            //NodeList that represents the array of "Profile" tags.
            XmlNodeList profiles = root[0].ChildNodes;

            //For each Profile tag, all fields will be gathered into a Profile object.
            foreach (XmlElement profile in profiles)
            {
                Profile prof = new Profile();

                //XmlElement.GetElementsByTagName allows us to get the tags by name.
                //XmlElement.GetElementsByTagName("")[0] allows us to get the first (and in this case, the only one) tag.
                //XmlElement.GetElementsByTagName("")[0].InnerText allows us to get the text within that tag.

                prof.Name = profile.GetElementsByTagName("Name")[0].InnerText;
                prof.EmployeeId = int.Parse(profile.GetElementsByTagName("EmployeeId")[0].InnerText);
                prof.Birthdate = DateTime.Parse(profile.GetElementsByTagName("Birthdate")[0].InnerText);

                //I add the Profile to the list.
                profilesList.Add(prof);
            }

            return profilesList;
        }
    }

Next time, we’re going to learn how to read it in a more “sophisticated” and eficient way using Linq.