Working with SharePoint People Pickers with jQuery: A New Function Called findPeoplePicker

[notice]2012-09-07 – Note that I’ve added a more robust version of this function into SPServices v0.7.2, which at this writing is in beta but will be released soon. See the docs for SPFindPeoplePicker.[/notice]

I was working with several People Pickers in a form for a client project last week where I needed to set or get their values at various times in the page lifecycle. These things are pesky little compound controls, I often need to find them in the page, and I get tired of writing new script every time I want to do it. I’ve posted in the past about how to get the value with JavaScript, set the value with JavaScript, set one with jQuery, and more. It seemed high time to just write a little function to give me everything I needed in one go.

Here’s what I came up with:

[important]UPDATE 2012-04-24 – I made a dumb mistake by using :contains() in the selector for thisRow, which occasionally returned unwanted results. I fixed it with the .filter() function below.[/important]

// Find a People Picker in the page
// Returns references to:
//   row - The TR which contains the People Picker (useful if you'd like to hide it at some point)
//   contents - The element which contains the current value
//   currentValue - The current value if it is set
//   checkNames - The Check Names image (in case you'd like to click it at some point)
$.fn.findPeoplePicker = function(options) {

  var opt = $.extend({}, {
    peoplePickerDisplayName: "",	// The displayName of the People Picker on the form
    valueToSet: "",			// The value to set the People Picker to. Should be a string containing each username or groupname separated by semi-colons.
    checkNames: true			// If set to true, the Check Names image will be clicked to resolve the names
  }, options);

  // Find the row containing the People Picker
  var thisRow = $("nobr").filter(function() {
    return $(this).text() == opt.peoplePickerDisplayName;
  }).closest("tr");
  var thisContents = thisRow.find("div[Title='People Picker']");
  var thisCheckNames = thisRow.find("img[Title='Check Names']:first");
  if(opt.valueToSet.length > 0) thisContents.html(opt.valueToSet);
  if(opt.checkNames) thisCheckNames.click();
  var thisCurrentValue = thisContents.text();

  return {row: thisRow, contents: thisContents, currentValue: thisCurrentValue, checkNames: thisCheckNames};
}

This function doesn’t just find the People Picker in the form, it also allows you to set it and, if you choose, click the Check Names image automagically. It also returns a JSON object which contains references to the important elements which make up the People Picker so that you can work with them later. Unfortunately, the only thing I can key on to find the darn things in the page is the <nobr> element which contains the DisplayName of the column. There’s just not anything else in the People Pickers which distingishes them from each other other than the standard comment, like so:

<!--  FieldName="Site Contact"
			 FieldInternalName="Site_x0020_Contact"
			 FieldType="SPFieldUser"
		   -->

Uising that comment has always seemed even less reliable to me than the DisplayName, even though I select for it in SPServices in several places. (If I’m missing something, please let me know.)

Here are a few example calls:

// Set the Site Contact to the current user
siteContactPeoplePicker = $().findPeoplePicker({
  peoplePickerDisplayName: "Site Contact",
  valueToSet: $().SPServices.SPGetCurrentUser()
});
// Find the Stakeholders People Picker in the form for later us
stakeholdersPeoplePicker = $().findPeoplePicker({
  peoplePickerDisplayName: "Stakeholders",
  checkNames: false
});

In the first call, I’m setting the Site Contact to the current user and resolving the name. In the second call, I’m getting references to the important objects for the StakeHolders People Picker so that I can set the value variably later, like so:

// Set the Stakeholders column value
stakeholdersPeoplePicker.contents.html(stakeholderNames);
stakeholdersPeoplePicker.checkNames.click();

I think some variation of this would be helpful to add to SPServices, even though it has nothing to do with the Web Services. Would you use it? What else would you want it to do?

53 Comments

  1. Marc,
    Personally, I find this method to be useful and bet others will too… I remember correctly, I have seen forum threads on how to get and access user field information on a standard SP forms.

    I also have a jQuery plugin that can be used on custom UI’s to turn an input field into a “People field”… It uses jQuery UI’s autocomplete plugin to allow the user to start typing the Person’s name and suggest items to select. The input field is updated with the proper format of id;#name entries that can be used with WebServices to update the item.

    Paul

    Reply
  2. Marc,

    Excellent work – I just played with this and it works like a charm!!!

    Having seen so many postings where the solutions were only valid if there was just one People Picker on the page, this is exceelent to have a multipurpose tool!

    Thanks!

    Reply
    • Will266:

      Thanks! I have a newer version which also returns the users’ account, email, and SIP in the JSON object. I’ll post it as soon as I do a little more debugging, and it’ll end up in SPServices.

      M.

      Reply
  3. Hmmm…I can’t seem to get this to work. I’m new to SharePoint, javascript, & jquery, so maybe I’m not calling your functions correctly. The “User” people picker on my form is not getting updated. When I debug, no errors are thrown.

    _spBodyOnLoadFunctionNames.push(“fillDefaultValues”);

    function fillDefaultValues()
    {
    var queryVal = $().SPServices.SPGetQueryString();
    //alert(queryVal['UID']);

    userPicker = $().findPeoplePicker({
    peoplePickerDisplayName: “User”, valueToSet: queryVal['UID']});
    }

    $.fn.findPeoplePicker = function(options) {

    var opt = $.extend({}, {
    peoplePickerDisplayName: “”, // The displayName of the People Picker on the form
    valueToSet: “”, // The value to set the People Picker to. Should be a string containing each username or groupname separated by semi-colons.
    checkNames: true // If set to true, the Check Names image will be clicked to resolve the names
    }, options);

    // Find the row containing the People Picker
    var thisRow = $(“nobr”).filter(function() {
    return $(this).text() == opt.peoplePickerDisplayName;
    }).closest(“tr”);
    var thisContents = thisRow.find(“div[Title='People Picker']“);
    var thisCheckNames = thisRow.find(“img[Title='Check Names']:first”);
    if(opt.valueToSet.length > 0) thisContents.html(opt.valueToSet);
    if(opt.checkNames) thisCheckNames.click();
    var thisCurrentValue = thisContents.text();

    return {row: thisRow, contents: thisContents, currentValue: thisCurrentValue, checkNames: thisCheckNames};
    }

    Reply
  4. Awesome ! I am using this now and would definitely use it in a future edition of SPServices.
    Great work again Marc – you’re a lifesaver.

    Reply
  5. I had to tweak the filter function to get it to work:

    return $(this).text().indexOf(opt.peoplePickerDisplayName) != -1;

    Reply
    • Aaron:

      I’ve taken this function further in the current alpha for v0.7.2. The filter is now this:
      var thisRow = $("nobr").filter(function() {
      // Ensures we get a match whether or not the People Picker is required (if required, the nobr contains a span also)
      return $(this).contents().eq(0).text() == opt.peoplePickerDisplayName;
      }).closest("tr");

      If you have a chance to try the alpha, I’d appreciate it. I spotted issues with Firefox yesterday that I’m working on, but it should be good in IE.

      M.

      Reply
  6. Hi Marc,

    I just added this little fuction on my help desk, this works like a charm.
    I spotted a little issue, in ” find(“div[Title='People Picker']“) ”
    If your Sharepoint site is not in english it won’t work. I juste had to rename it the good way (“Sélecteur de personnes” in french) and here we go. I’ve also done the same thing with ” find(“img[Title='Check Names']:first”) “.

    Thanks for your good work.

    Reply
    • Thomas:

      The version in this post was my first crack at it. I’ve got a more robust version in the v0.7.2 alpha. It will have the same issue with the French, though. Unfortunately, I can’t test in with all of the language packs.

      M.

      Reply
      • As I am using a multiple selector to comply with multiple languages and I’m new to jquery, I wondered if there was a way to use regex in selectors ?

        Reply
  7. Marc
    I am using the above code and I am very new to Sharepoint. My need is I enter or use people picker to get the person name which displays in the Personname column which people or group type. i need to read this personame value from this column and do lookups. This below code is giving Object [object Object] has no method ‘findPeoplePicker’.. Can you please help.

    $(document).ready(function() {
    $(“#btnbutton”).click(
    function() {

    PersonNamePeoplePicker = $().findPeoplePicker({
    peoplePickerDisplayName: “PersonName”,

    checkNames: false

    });

    $.fn.findPeoplePicker = function(options) {

    alert(‘ r u here’);
    var opt = $.extend({}, {

    peoplePickerDisplayName: “PersonName”, // The displayName of the People Picker on the form

    valueToSet: “PersonName”, // The value to set the People Picker to. Should be a string containing each username or groupname separated by semi-colons.

    checkNames: true // If set to true, the Check Names image will be clicked to resolve the names

    }, options);

    // Find the row containing the People Picker

    var thisRow = $(“nobr”).filter(function() {
    alert(opt.peoplePickerDisplayName);
    return $(this).text() == opt.peoplePickerDisplayName;

    }).closest(“tr”);

    var thisContents = thisRow.find(“div[Title='People Picker']“);
    alert(thisContents);
    var thisCheckNames = thisRow.find(“img[Title='Check Names']:first”);

    if(opt.valueToSet.length > 0) thisContents.html(opt.valueToSet);

    if(opt.checkNames) thisCheckNames.click();

    var thisCurrentValue = thisContents.text();
    alert(thisCurrentValue );
    return {row: thisRow, contents: thisContents, currentValue: thisCurrentValue, checkNames: thisCheckNames};

    }

    Reply
    • I’ve added an improved version of this function into the beta of SPServices v0.7.2. You should check that version out, as there’s some better documentation as well (though not final yet).

      The function does indeed return an object, as there is a set of useful information returned. It’s more a JavaScript thing to understand than a SharePoint thing.

      M.

      Reply

Leave a Reply