Using multiple PeoplePicker’s in SharePoint 2013 Hosted App with AngularJS MVVM

So I’ve been cranking out more features for my App that I’m going to be walking through at #SPC14. There is great a great sample Visual Studio 2013 Project that shows how to use the PeoplePicker in a SharePoint 2013 Hosted App. Hats off to the team on the content and the code samples that are out there really help to get you started and see how things hang together. Where I found the code sample (and the MSDN page) fell short was how to support multiple PeoplePicker’s on one page.

I am building out a App for the Store that will render List Items which has a inline edit mode and I needed a People Picker for each item shown. I’ve built this using a view and then binding it to the collection of List Items I get back from my REST query which I discussed in my last post.

There were a few steps I had to take to get this going:

Step 1 – reference the JavaScript files

I had to use the ScriptLink to pull in the relevant JavaScript files, I found that the top 4 I hadn’t referenced already in my App and aren’t there in a net new project by default:

Step 2 – Add the PeoplePicker DIV Element

At first it looks odd to just be adding a DIV to a page that is a control used in a form, but low and behold it works. You’ll notice that I’m adding it as a JavaScript string to my View that I had blogged about earlier this month. Not that I have added the “{{todo.id}}” to the ‘id’ attribute of the DIV, this ensures each DIV is unique based on the ID of the List Item.

I did try and bind it to the ng-model of the List Item ‘AssignedTo’ element like my other Edit Form fields, but unfortunately the nature of this control doesn’t work like that.

Step 3 – Hook up the Edit click to bind to the model

I had to call the initializePeoplePicker function and pass in the DIV name, which you can see is appended by the unique ID of the List Item. I pass in the AssignTo Display Name and User Name also. I decided only to call this as and when it went into EditMode rather than calling this up front for the hidden DIVs.

Step 4 – Modify the initializePeoplePicker

I had to tweak this method that was provided in the code sample to cater for multiple PeoplePicker DIVs on the page.

The key with the above function is that I set the users variable to null first and only populate it if I pass in a user name. This means that the PeoplePicker will be empty if no User name is assigned to in the List Item. I also set MultipleValues to false as I only want one User in the AssignedTo.

Step 5 – tweak getUserInfo(id)

I also tweaked the getUserInfo function so that it can find the DIV based on the unique ID of the List Item and then return the UserInfo variable.

 Step 6 – formatting the UserInfo so JSOM (Javascript CSOM) can parse it

One of the big things that blocked me for a while was how to convert the UserInfo object to something that the JSOM List Item Update() would understand. I leveraged the ‘SP.FieldUserValue.fromUser’ and passed in the UserInfo relevant information (format was ‘domain\\username’.

Note that I also update the ng-model binding for the assignedTo there also with the Display Name.

Wrapping Up

If you’re coming to the SharePoint Conference 2014, I look forward to seeing you there. I encourage you to come to my session as these are only tidbits into a much deeper discussion on the journey I took to build this SharePoint Hosted App with AngularJS for the Office Store.

11 thoughts on “Using multiple PeoplePicker’s in SharePoint 2013 Hosted App with AngularJS MVVM”

  1. Hi Jeremy,

    after using the people picker I was wandering if there is a better way to initialize users in the people picker.

    I wanted to be sure to add users / groups with the correct properties. To me it seems like a bit complicated to create a user object and to know which properties need to be filled.

    So I loaded the client people picker and the I got the people picker object from the page

    var peoplepicker = SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan

    after that I could do the following (SharePoint Online):

    peoplepicker.AddUserKeys(‘i:0#.f|membership|name@domain.onmicrosoft.com’);

    in that case you only need to have the user id.

    If you want to add multiple users:

    peoplepicker.AddUserKeys(‘i:0#.f|membership|name01@domain.onmicrosoft.com;’i:0#.f|membership|name02@domain.onmicrosoft.com’);

    so you use a string with a “;” seperator.

  2. What if I have a Sharepoint Hosted app that doesn’t use .aspx, but is rather just a .htm file? Have you had any experience with getting this to work, without using ScriptLinks?

    If I just reference the .js files directly, I get script errors, likely related to some kind of loading order I need to now abide by, but I have no clue what order that would be.

  3. Jeremy, thanks so much for the quick response. I’ll take a look at this. Not sure if I’ll be able to use it, as our app is intended to run on both O365 and on-premises SP13, but I may be able to gleam a bit more from it, at the same time.

    1. I am not sure when this stuff will be in on-premises, when I’m onboard at Microsoft I will be sure to get an update for you on this in coming weeks (which will probably be too late). For our Provider Hosted App we built at AvePoint, we have to build the people picker ourselves. We used a combination of the Search API (to return users) as teh User Profile API doesn’t have a query engine so was slower to iterate through and check for the user.

      1. It’s funny you should mention that. After your response to me yesterday, that’s what I decided to set out to do first, before trying to look at the o365 post you referenced.

        I’m nearly complete with it, but it’s the select2 (http://ivaynberg.github.io/select2/index.html) component doing a $filter grab on Title against /_api/web/siteusers/ and that seems to be working quite well. Maybe I’ll post my solution here for your consideration.

        1. Here is the sample function that we pretty much settled on. It essentially gives you a “progressive search” drop down for site users:

          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’));
          });
          }

Leave a Reply