Tuesday, May 26, 2015

Adding a User to Multiple Groups

In SharePoint 2013 using JQuery and the People Picker Control

The Problem

You have a SharePoint site with a large number of groups.  In our case, the groups are there to support highly granular document notifications, where a specific group needs to be notified when certain document groups are modified.
If you use the default SharePoint client interface, adding a user to multiple groups can be cumbersome and time consuming as you are only able to do it one at a time.  Of course, there are powershell and server side ways of doing this, but we needed a client interface that would allow us to select a user, then select multiple groups to either add or remove. 
This solution provides that interface.

Resources

This post is based on a number of resources.
 
Blog post that describes groups components of solution:

 
Microsoft Documentation on People Picker Control:
 
Stack Exchange Question and answer about adding a people picker to a custom web part:

 

Functionality

 
STEP ONE:
User Navigates to page with Picker and groups controls embedded.  All controls are empty (no values).

 
STEP TWO:
User enters name or email address in people picker.  People picker resolves user.

 
STEP THREE:
User clicks “Get User’s Groups” and groups controls are populated.  Control on left marked “Available Groups” contains all groups from current site that user is NOT a member of.  Control on right marked “Assigned Groups” contains all groups the identified user currently belongs to.

 
STEP FOUR:
User can select as many groups as needed from available groups.  Clicking the double arrow button pointing right results in user being added to those groups.

 
STEP FIVE:
User can select as many groups to remove the member from as they wish on the right site control, clicking the double arrow button pointing left results in users being removed from all groups specified.

 

Script Libraries

Depending on your approach to hosting the page, you may need to add these script libraries at the top of your HTML.  If you added these components to a web part page, these libraries are included.  If you create a standalone page, you will need to add these references:
<SharePoint:ScriptLink name="clienttemplates.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="clientforms.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="clientpeoplepicker.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="autofill.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="sp.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="sp.runtime.js" runat="server" LoadAfterUI="true" Localizable="false" />
    <SharePoint:ScriptLink name="sp.core.js" runat="server" LoadAfterUI="true" Localizable="false" />
 

 

JQuery Libraries

You will need to have the two JQuery Libraries imported on your page to provide functionality.  I have my libraries hosted in the local site assets folder, so my links look like this:
These links are pasted into the “PlaceHolderAdditionalPageHead” on my page, place them as appropriate for your context.
<script src="../SiteAssets/jquery-1.11.3.js" type="text/javascript"></script>
<script src="../SiteAssets/jquery.SPServices-2014.02.js" type="text/javascript"></script>

 

HTML Markup

The HTML markup used on the SharePoint page can be inserted into a content editor webpart, or embedded through designer if you so choose.  I chose the latter option and added to the ContentPlacedholderMain section of my SharePoint page.
The HTML Markup is as follows:
<table align="center">
              <tr>
                        <td colspan="3" align="right">
                                    <table align="Center">
                                                <tr>
                                                            <td>User:&nbsp;<div id="peoplePickerDiv"></div></td>
                                                            <td><br/><input type="button" value="Get User's Groups" onclick="getUserInfo()"></input></td>
                                                </tr>
                                    </table>
                        </td>
              </tr>
              <tr><td><br/><br/></td></tr>
              <tr> 
                <th class='ms-vh2'>Available Groups</th> 
                <th></th> 
                <th class='ms-vh2'>Assigned Groups</th> 
              </tr> 
              <tr> 
                <td class='ms-vb2'> 
                  <select id="my_SPGroupsAvailable" style="width:400px;height:500px;" multiple="multiple"></select> 
                </td> 
                <td> 
                  <button id="my_AddGroupsToUser" type="button" style="width:80px;" onclick="AddGroupsToUser()">
                                    &gt;&gt;</button><br/><br/> 
                  <button id="my_RemoveGroupsFromUser" type="button" style="width:80px;" onclick="RemoveGroupsFromUser()">
                                    &lt;&lt;</button></td> 
                <td class='ms-vb2'> 
                  <select id="my_SPGroupsAssigned" style="width:400px;height:500px;" multiple="multiple"></select> 
                </td> 
              </tr> 
            </table>
 
The people picker is identified by the peoplePickerDiv, Available Groups and Assigned groups divs contain the two group collections for the chosen user.

 

Javascript

The javascript that supports the functionality described is pasted below.  Examine the comments for details on functionality.
// Run your custom code when the DOM is ready.
                        $(document).ready(function () {
                            // Comment out the below line to ensure JS loading
                            //alert("Document Ready Function Run.");
                            // set up the people picker ready for use using control div
                            initializePeoplePicker('peoplePickerDiv');
                            //
                        });
                       
                        // PEOPLE PICKER JAVASCRIPT
                       
                        // Render and initialize the client-side People Picker.
                        function initializePeoplePicker(peoplePickerElementId) {
                                    // Create a schema to store picker properties, and set the properties.
                            var schema = {};
                            schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup';
                            schema['SearchPrincipalSource'] = 15;
                            schema['ResolvePrincipalSource'] = 15;
                            schema['AllowMultipleValues'] = false;
                            schema['MaximumEntitySuggestions'] = 50;
                            schema['Width'] = '280px';
                       
                            // Render and initialize the picker.
                            // Pass the ID of the DOM element that contains the picker, an array of initial
                            // PickerEntity objects to set the picker value, and a schema that defines
                            // picker properties.
                            this.SPClientPeoplePicker_InitStandaloneControlWrapper(peoplePickerElementId, null, schema);
                        }
                       
                        // Query the picker for user information.
                        function getUserInfo() {
                                    //alert("Get user info clicked");
                            // Get the people picker object from the page.
                            var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
                       
                            // Get information about all users.  Only use first user entered.
                            // control settings prevent entry of multiple users (schema['AllowMultipleValues'] = false;)
                            // this approach left here to allow further customizing
                            var users = peoplePicker.GetAllUserInfo();
                       
                                    // if the user array has an element
                                    if(users.length > 0) {
                                                RefreshGroupLists(users[0].Key);
                                    } else {
                                                alert("No user entered.  Enter name or email address into user field.");
                                    }
                        }
                        // END OF PEOPLE PICKER JAVASCRIPT
                       
                        // START OF GROUPS CONTROLS JAVASCRIPT
                        // Populate groups lists based on loginName of user identified in people picker
                        function RefreshGroupLists(loginName){
                          var strHTMLAvailable = "";
                          var strHTMLAssigned = "";
                          var arrOptionsAssigned = new Array();
                          var intOpts = 0;
                          var booMatch;
                          var booErr = "false";
                          $("#my_SPGroupsAssigned").html("");
                          $("#my_SPGroupsAvailable").html("");
                          if($("#my_SiteUser").attr("value") == 0){
                            alert("You must select a user");
                            return;
                          }
                          // Populate the groups that the current user belongs to.
                          // populate the array that determines which groups are available (arrOptionsAssigned)
                          $().SPServices({ 
                           operation: "GetGroupCollectionFromUser", 
                                 userLoginName: loginName, 
                                 async: false, 
                                 completefunc: function(xData, Status)
                                 {
                                   $(xData.responseXML).find("errorstring").each(function() {
                                       alert("User not found");
                                       booErr = "true";

                                       return;
                                    });
                                    $(xData.responseXML).find("Group").each(function() {
                                        strHTMLAssigned += "<option value='" + $(this).attr("Name") + "'>" + $(this).attr("Name") + "</option>";
                                        arrOptionsAssigned[intOpts] = $(this).attr("Name");
                                        intOpts = intOpts + 1;

                                    });
                                    $("#my_SPGroupsAssigned").append(strHTMLAssigned); 
                           }
                          });
                          //Populate available site groups using current sites group collection, do not use groups identified by strOptionsAssigned array
                          if(booErr == "false"){
                            $().SPServices({ 
                                operation: "GetGroupCollectionFromSite", 
                                async: false, 
                                completefunc: function(xData, Status) { 
                                  $(xData.responseXML).find("Group").each(function() {
                                    booMatch = "false"; 
                                    for (var i=0;i<=arrOptionsAssigned.length;i++){ 
                                      if($(this).attr("Name") == arrOptionsAssigned[i]){ 
                                        booMatch = "true"; 
                                        break; 
                                      } 
                                    } 
                                    if(booMatch == "false"){ 
                                      strHTMLAvailable += "<option value='" + $(this).attr("Name") + "'>" + $(this).attr("Name") + "</option>"; 
                                    } 
                                  }); 
                                  $("#my_SPGroupsAvailable").append(strHTMLAvailable); 
                                }
                            }); 
                          }
                        } 
                       
                        // Take people picker identied user, iterate through groups array adding user to each group
                        function AddGroupsToUser(){
                          var i;  
                          //alert("add groups to user fired");
                          var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
                          var users = peoplePicker.GetAllUserInfo();
                          if($("#my_SPGroupsAvailable").val() == null){ 
                            alert("You haven't selected any groups to add"); 
                            return; 
                          } 
                          else{ 
                            var arrGroups = $("#my_SPGroupsAvailable").val();
                            for (i=0;i<arrGroups.length;i++){ 
                              $().SPServices({ 
                                  operation: "AddUserToGroup", 
                                  groupName: arrGroups[i], 

                                  userLoginName: users[0].Key, 
                                  async: false, 
                                  completefunc: null 
                              }); 
                            }
                            // repopulate page with updated groups
                            RefreshGroupLists(users[0].Key); 
                          } 
                        }   
                        // Take people picker identified user and remove from groups array removing user from each group
                        function RemoveGroupsFromUser(){ 
                          var i;  
                          //alert("remove groups from user fired");
                          var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
                          var users = peoplePicker.GetAllUserInfo();
                          if($("#my_SPGroupsAssigned").val() == null){
                            alert("You haven't selected any groups to remove"); 
                            return; 
                          } 
                          else{ 
                            var arrGroups = $("#my_SPGroupsAssigned").val(); 
                            for (i=0;i<arrGroups.length;i++){ 
                              $().SPServices({ 
                                  operation: "RemoveUserFromGroup", 
                                  groupName: arrGroups[i], 
                                  userLoginName: users[0].Key,
                                  async: false, 
                                  completefunc: null 
                              });
                            }
                            RefreshGroupLists(users[0].Key);

                          }
                        }

 

3 comments:

Unknown said...

Hi Steve,

I am not a programmer, but I wanted to use this to manage the users for our SharePoint site. So I added the Java script along with the table code as "Embedded code" in SharePoint 2013 Wiki page along with jQuery and SPServices references. But I do not get the "PeoplePicker" box to enter the user name or email address. Any help from you will be appreciated!Thanks!

steve said...

The JavaScript generates the people picker components on page load. Remove the comment slashes on the line at the beginning of the code that starts ALERT. Save and refresh you page. If an alert does not pop up that says "Document ready function run" then your jquery is not working. Your jquery references are probably wrong. You need to first download the libraries to a site assets folder then use that folder path in your embedded jquery references.

Unknown said...

Hi Steve,
I did remove the comment slashes and the alert does pop up. I have downloaded the jQuery and SPServices libraries, added to my SharePoint and using the path as reference.
Anything else which might be causing this? And as I said, I am not at all a programmer. Appreciate!

Post a Comment