When building an app for SharePoint 2013, it’s likely that a people-picker will be needed at some point.  Regardless of the chosen hosting model, there are challenges to using the standard People Picker control.  This is particularly true in the case where the app’s user interface has been implemented as a “naked” HTML page (as opposed to the Microsoft-provided Default.aspx page). While I’ve discovered there’s an alternate people-picker available, In the case of my app I had a legitimate interest in building my own.  In fact, to be a bit more precise, I had several goals:

  • Build a people picker that is hosted in a “naked” HTML page
  • Fully exploit the power of javascript and jQuery
  • Be able to take advantage of any of the numerous open-source javascript libraries that are avaiable

After some research and experimentation I settled on the following:

  • jQuery
  • Select2 –  a jQuery add-on that provides a replacement for select boxes – in particular it supports progressive search against a REST API
  • Bootstrap – a collection of tools for quickly building a responsive, web-based UI
  • SharePoint REST API

The HTML page I authored includes the following references:

<script type="text/javascript" src="../Scripts/libs/select2/select2.min.js"></script>
 <!-- Select2 CSS -->
 	<link rel="Stylesheet" type="text/css" href="../Scripts/libs/select2/select2.css" />
 	<link rel="Stylesheet" type="text/css" href="../Scripts/libs/select2/select2-bootstrap.css" />

Next, I added input type=’text’ to page.  Note that while Select2 works with select boxes in it’s most basic form, the control needs to be an input box of type text in order to exploit the built-in AJAX/REST search support.

<input type="text" id="peoplePickerDiv" class="form-control" />

Once my markup was in place I added the following function to bestow the “Select2” functionality on the input control:

function SetCustomPeoplePicker() {
  $("#peoplePickerDiv").select2({
     placeholder: "Search for a person",
     minimumInputLength: 3,
     ajax: {
         url: $.QueryString["SPAppWebUrl"] + "/_api/web/siteusers",
         dataType: "json",
         data: function (term, page) {
         return {
             "$filter": "substringof('" + term + "', Title)"
         };
     },
     results: function (data, page) {
       return { results: data.d.results };
     },
     params: {
       contentType: "application/json;odata=verbose",
       headers: {
         "accept": "application/json;odata=verbose"
       }
     }
   },
   id: function (person) { return { id: person.Id }; },
   formatResult: function (person) {
     return person.Title;
   },
   formatSelection: function (person) {
     return person.Title;
   },
   formatNoMatches: function () {
     return "No people found. (Case Sensitive)";
   },
   escapeMarkup: function (m) { return m; },
   dropdownCssClass: "bigdrop"
   }).on('change', function (e) {
     // Access to full data
     console.log($(this).select2('data'));
   });
}

A few things to point out in the above function:

  • This code uses SharePoint’s RESTful endpoint for site users (/_api/web/siteusers)  to get the set of site users for the app web.
  • The data function supplies parameters to the AJAX/REST call; of particular importance is the use of the  OData $filter parameter.
  • The SharePoint-supplied  substringof() function is to populate the $filter parameter. Inexplicably, this function treats data in a case-sensitive fashion!
  • params and headers property must be supplied as shown above.
  • The id property must be supplied as shown above, otherwise the returned results will not be selectable.
  • Note that the change event handler demonstrates how to pull the selected value and its accompanying data.
  • The RESTful endpoint for pulling site users does not search through user accounts that have not logged into SharePoint yet (unlike the SharePoint people picker, which shows all accounts).

Building your own people-picker lets you “have if your way” and provide a rich set of functionality for “picking people” in SharePoint.