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?

Working with the People Picker: A Shortcut

The People Picker is the control you see on the page when a column or field needs to contain a user. (Not just the text representing a user’s name, which you should really almost never do, but the actual user object as understood by SharePoint.)

It looks something like this. (This is an example from the Add Users page for Site Permissions.)
image

Most people are used to working with the People Picker in one of two ways:
1) Typing all or part of a user name in the box and clicking on the Check Names icon People Picker - Check Icon .

 image

At this point, when they see the ‘No exact match was found.’ message, most people move on to option 2.

2) Clicking on the Browse icon People Picker - Lookup Icon and looking people up in the Select People and Groups dialog box.

image

There’s a third way which can be quicker. You can just type a part of the user’s name in the box and hit enter or the Check Names icon, as in option 1) above. When you get the ‘No exact match was found.’ message, click on the name which has been underlined with the squiggly red line.

image

While there was no exact match found, there were matches, you’ll see them, and you can select the one you want.

Keep in mind that the more specific you can be in what you type the better the results will be, much like you are used to in your email client, whether it is Outlook, Gmail, Lotus Notes, or whatever.

Set a People Picker’s Value on a Form – Revisited with jQuery

Jim Bob Howard (@jbhoward) always asks me good questions.  Today he was interested in setting the value of a People Picker on a form with script.  I pointed him at my old post about doing it with JavaScript, but we’re jQuery buddies, so I wanted to give him some jQuery instead. That and the fact that jQuery will be more reliable.  (Jim Bob was already using jQuery on the page. If he wasn’t I would have suggested sticking with the JavaScript approach; no need for the overhead if JavaScript will do.)

Here’s the jQuery I came up with:

var columnName = 'yourcolumnname';
var userName = 'domain\\username';

// There's no easy way to find one of these columns; we'll look for the comment with the columnName
var searchText = RegExp("FieldName=\"" + columnName + "\"", "gi");
// Loop through all of the ms-formbody table cells
$("td.ms-formbody").each(function() {
    // Check for the right comment
    if(searchText.test($(this).html())) {
        $(this).find("div[Title='People Picker']").html(userName);
        return false;
    }
});

Set a People Picker’s Value on a Form

Following up on my recent post about getting the current value of a People Picker on a form, today I built the JavaScript to set the value, and here it is. As usual, I’ve left in my debugging code in case you want to see how it works.

// setPickerInputElement: Set a People Picker's value using its identifier to find it in the page
// Arguments:
//                            identifier:            The identifier for the instance of the fieldName (ff1, ff2, etc.)
//                            value:                    Set the fieldName to this value
//

function setPickerInputElement(identifier, value) {
  var tags = document.getElementsByTagName('DIV');

  for (var i=0; i < tags.length; i++) {
    var tempString = tags&#91;i&#93;.id;
    //alert('tags&#91;' + i + '&#93;.id = ' + tempString);
    if ((tempString.indexOf(identifier) > 0) && (tempString.indexOf('UserField_upLevelDiv') > 0)){
      //alert('HIT for ' + identifier + ' id=' + tags[i].id + ' value=' + tags[i].value);
      tags[i].innerHTML = value;
      break;
    }
  }
}

Get a People Picker’s Current Value on a Form

There’s a nice article over at the SharePoint Designer Team Blog about how to manipulate a List Form Field (AKA Data Form Field) using Javascript.  It gives some great methods to accomplish this, but if you’d like to get the current value of a People Picker on a form (for validation purposes, most likely), the info isn’t there to do so reliably.  I had to do this today, so I wanted to post what I came up with. As usual when I post these things, I’ve left in the alerts that I used for debugging in case it helps you.

// Find a People Picker’s value using its identifier (ff1, ff2, etc.)to find it in the page
function getPickerInputElement(identifier) {
  var tags = document.getElementsByTagName(‘DIV’);
  for (var i=0; i < tags.length; i++) {    var tempString = tags[i].id;    //alert('tags[' + i + '].id = ' + tempString);    if ((tempString.indexOf(identifier) > 0) && (tempString.indexOf(‘UserField_upLevelDiv’) > 0)){
    //alert(‘HIT for ‘ + identifier + ‘ id=’ + tags[i].id + ‘ value=’ + tags[i].value);
    var innerSpans = tags[i].getElementsByTagName(“SPAN”);
    for(var j=0; j < innerSpans.length; j++) {      //alert('innerSpans[' + j + '].id = ' + innerSpans[j].id);      if(innerSpans[j].id == 'content') {       //alert('HIT for ' + identifier + ' id=' + innerSpans[j].id + ' innerHTML=' + innerSpans[j].innerHTML);       return innerSpans[j].innerHTML;      }     }      }   }   return null;  }[/sourcecode]