2

I use SharePoint 2013. I need advice to bind clientpeoplepicker control with a field. By default, user field on list form is displayed same as SharePoint:ClientPeoplePicker. So we have autocomplete functionality. All fields are generated by WebPartPages:ListFormWebPart. But i created new display form and saw, that now fields is generated using WebPartPages:DataFormWebPart. And inside WebPartPages:DataFormWebPart any field is created using SharePoint:FormField control. And now i see, that user field is displayed as the old SharePoint 2010 user field, i.e. without ability to autocomplete. I can add SharePoint:ClientPeoplePicker control to custom form. But he is not have a parameter to set appropriate field for him. This means that the value of WebPartPages:DataFormWebPart will not be saved.

I have solution. I dont think that is a best way, but he is working. On custom form i added SharePoint:ClientPeoplePicker control near SP2010 peoplepicker control (Which not have autocomplete), that was hided. And on PreSaveAction() i take value from SharePoint:ClientPeoplePicker and put it in SP2010 peoplepicker control. So, value from SharePoint:ClientPeoplePicker is saved to user field in list item.

Can anyone suggest a better solution? Thanks in advance!

7
  • 1
    has anyone solved this?
    – wayzz
    Nov 13, 2015 at 9:06
  • Try to use solution proposed in last paragraph. It's works fine. But i wrote additional javascript code to move values between old and new peoplepicker control's. Nov 13, 2015 at 9:57
  • is there a tutorial you have followed? I understand what you did and have found that this solution has been used many times but I still have a problem with the JS syntax.
    – wayzz
    Nov 13, 2015 at 14:07
  • I can provide java script code snippet here for you. You need this? Nov 13, 2015 at 14:12
  • 1
    yes it helps please
    – wayzz
    Nov 13, 2015 at 14:28

3 Answers 3

5

Solution:
On custom form i added SharePoint:ClientPeoplePicker control near SP2010 peoplepicker control (Which not have autocomplete), that was hided.
Markup to add sharepoint:clientpeoplepicker:

    <sharepoint:clientpeoplepicker allowemailaddresses="true" allowmultipleentities="true" clientidmode="Static" cssclass="ms-long ms-spellcheck-true" height="85px" id="UserFieldCPP" initialhelptext=" " principalaccounttype="User,DL,SecGroup,SPGroup" required="false" rows="1" runat="server" validationenabled="true" visiblesuggestions="3">  

Add on PreSaveAction() javascript function. Put code below to PreSaveAction().
Additionaly, i use spservices js library.
And before saving form, code below move values from old to new peoplePicker:

    var arrUserField = [];  
    $("#UserFieldCPP_TopSpan span span span[class='ms-entity-resolved']").each(function(index, elem)
    {  
            arrUserField.push($(this).text());  
    });  
    var strUserField = arrUserField.join(";");  

    $().SPServices.SPFindPeoplePicker({  
             peoplePickerDisplayName: "Сотрудник",  
             valueToSet: strUserField ,  
             checkNames: true  
    });

Code above is for saving data. On form load add code below:

    var UserFieldPP = $().SPServices.SPFindPeoplePicker({  
            peoplePickerDisplayName: "Сотрудник"   
    });  

    var UserFieldPPPeopleList = UserFieldPP.currentValue.split(";");  
    UserFieldPPPeopleList.pop();   
    var picker = SPClientPeoplePicker.SPClientPeoplePickerDict["UserFieldCPP_TopSpan"]  

    for (i = 0; i < UserFieldPPPeopleList.length; i++) {   
            var name = UserFieldPPPeopleList[i];  
            $("#UserFieldCPP_TopSpan_EditorInput").val(name);  
            picker.AddUnresolvedUserFromEditor(true)  
    }  
0
1

Based on the above answer by Alexander, this is the best I could come up with for a general SharePoint Designer solution. In the form of ASP tags in XSLT, you create the people picker pairs (SP2010 and SP2013) like so:

<SharePoint:FormField runat="server" ID="_START_Attendees_END_" ControlMode="Edit" FieldName="Attendees"/>
<SharePoint:ClientPeoplePicker runat="server" ClientIDMode="Static" AutoFillEnabled="True" ID="Attendees"  ValidationEnabled="True" PrincipalAccountType="User" Rows="1" AllowMultipleEntities="True" CssClass="ms-long ms-spellcheck-true"/>

The FormField control is the one that is bound to the list column. It has the FieldName property on its API. For reasons of inheritance, the ClientPeoplePicker control does not. That's why it can't be bound directly to a list column. Kinda poorly designed really. Anyway, on the ClientPeoplePicker we use ClientIDMode="Static" to make it easier to select the rendered elements. ClientIDMode doesn't have the same effect in the FormField control, so there's no point using it. We need to be clever with the ID.

The technique I came up with is to use predictable tokens that will match a regular expression but not collide with anything. I chose a prefix of "START" and a suffix of "END". In between those tokens, we use the same string as the ClientPeoplePicker ID, which in this example is also the same as the FormField FieldName attribute, though it doesn't need to be. With fields setup in this way we then hide the old style pickers on the form using CSS and use jquery to copy values between the old and new. The javascript function PreSaveAction() will execute before the form is saved. In this function we copy values from the new style pickers to the old style ones. We can use the jQuery $(document).ready method to do the reverse when the form loads. Code is shown below and can be introduced through a Script Editor web part on the form page, written into the XSLT, or included through external files. It will work for any custom forms designed in this way.

<script type="text/javascript" src="/_layouts/15/clientforms.js">  </script>
<script type="text/javascript" src="/_layouts/15/clientpeoplepicker.js"></script>
<script type="text/javascript" src="/_layouts/15/autofill.js"></script>
<script type="text/javascript">
function PreSaveAction() { 
    for (var key in SPClientPeoplePicker.SPClientPeoplePickerDict) {
         var pickerObj = SPClientPeoplePicker.SPClientPeoplePickerDict[key];
         // drop the _TopSpan
         var customID = key.substr(0, key.length -  8);
         $('div[id*="_START_' + customID + '_END_"]').html(pickerObj.GetAllUserKeys());
    }

    return true;
}

$(document).ready(function() {
    var oldStylePickers = $('div[id*="UserField_upLevelDiv"]');
    var regexp = /_START_(.*?)_END_/;
    oldStylePickers.each(function() {
        var $div = $(this);
        var userKeys = [];
        $div.find('span.ms-entity-resolved').each(function() {
            userKeys.push($(this).attr('title'));
        });
        //alert(userKeys);
        var matches = regexp.exec(this.id);
        if (matches && matches.length > 1) {
            var newPickerID = matches[1];
            var pickerObj = SPClientPeoplePicker.SPClientPeoplePickerDict[newPickerID + '_TopSpan'];
            for (var i=0; i < userKeys.length; i++) {
                var login = userKeys[i];  
                pickerObj.AddUserKeys(login);
            }
        }
    });
});
</script>
<style type="text/css">
span.ms-usereditor {
    display: none;
}
</style>

I hope this helps someone. I couldn't find a complete solution anywhere and spent a fair bit of time on this.

1

The above posts helped me pretty much, but i was adding the control in a custum page layout and in there you don't have the PreSaveAction.

Therefore i changed the PreSaveAction method to CopyPeopleToOldControl and placed this code beneath the IF loop. Now when i lose the focus on the user field the values are automaticly copied to the hidden field.

$("#" + newPickerID + '_TopSpan').focusout(function() {
    CopyPeopleToOldControl();
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.