8

I'm working on a custom form that uses a people picker. I started by using InfoPath to customize the form. Of course when I did this SharePoint stopped using the nice people picker field that provides names/predictive text, the name as you go, making it easier for users.

I deleted the InfoPath form and began creating my form using SharePoint Designer and a NewFormXX. Again, the people picker changes to the less desirable picker.

Is there a way to either use InfoPath or SharePoint designer to customize a form AND use the nice predictive text people picker?

  • yeah the people picker with the two stage verification and no predictive is the worst. Really want to use the nice one if there is a way. – Rothrock Oct 26 '15 at 21:06
  • Is this custom form connected to a List? – Emiliano Poggi Nov 3 '15 at 18:47
2
+50

Mark Rackley has a brilliant guide on custom forms that I've used in the past. I suggest you check it out:

http://www.markrackley.net/2013/08/29/easy-custom-layouts-for-default-sharepoint-forms/

The two basic elements you need are his JavaScript and your own HTML layout for your form. I'll copy the key bits from the article below.

Here’s the script I wrote that is responsible for moving the contents of the form fields into your custom layout. You don’t necessarily need to understand what it’s doing, just make sure to include it on your page.

<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>

<style type="text/css">
  .ms-formtable
  {display:none;}
</style>

<script type="text/javascript">
    $(document).ready(function() {
        //loop through all the spans in the custom layout        
        $("span.hillbillyForm").each(function()
        {
            //get the display name from the custom layout
            displayName = $(this).attr("data-displayName");

            displayName  = displayName.replace(/&(?!amp;)/g,'&amp;');
            elem = $(this);
            //find the corresponding field from the default form and move it
            //into the custom layout
            $("table.ms-formtable td").each(function(){
                if (this.innerHTML.indexOf('FieldName="'+displayName+'"') != -1){
                    $(this).contents().appendTo(elem);
                }
            });
        });
    });
</script>

So, the key that makes this all work is that the script is looking for each “span” in your custom layout that has the class “hillbillyForm”. This special span is the placeholder for your SharePoint Form input/display field.

The script then looks for a custom attribute in this span called “data-displayName”. The value of this attribute is the DISPLAY NAME of the SharePoint Form field for which the span is a placeholder

So, all you have to do is design a form using standard html, with css, and whatever you want, and put this special span where you want the field input to appear making sure to put in the correct display name for that field.

Here’s my super basic HTML form. I’m just using an old school table that basically turns the default form into a two column form.

<h1>New Issueh1>
<table cellpadding="5" cellspacing="5" bgcolor="#FFFFCC" >
    <tr >
        <td>
            <b>Title:b><br>
            <span class="hillbillyForm" data-displayName="Title">span>
        td>
        <td>
            <b>Issue Status:b><br>
            <span class="hillbillyForm" data-displayName="Issue Status">span>
        td>
    tr>
    <tr >
        <td>
            <b>Assigned To:b><br>
            <span class="hillbillyForm" data-displayName="Assigned To">span>
        td>
        <td>
            <b>Priority:b><br>
            <span class="hillbillyForm" data-displayName="Priority">span>
        td>
    tr>
    <tr >
        <td>
            <b>Description:b><br>
            <span class="hillbillyForm" data-displayName="Description">span>
        td>
        <td valign="top">
            <b>Category:b><br>
            <span class="hillbillyForm" data-displayName="Category">span>
            <b>Alert Me:b><br>
            <span class="hillbillyForm" data-displayName="Alert Me">span>
            <b>Blame:b><br>
            <span class="hillbillyForm" data-displayName="Blame">span>
        td>
    tr>
    <tr >
        <td>
            <b>Related Issues:b><br>
            <span class="hillbillyForm" data-displayName="Related Issues">span>
        td>
        <td valign="top">
            <b>Due Date:b><br>
            <span class="hillbillyForm" data-displayName="Due Date">span>
        td>
    tr>
    <tr >
        <td>
            <b>Comments:b><br>
            <span class="hillbillyForm" data-displayName="Comments">span>
        td>
        <td valign="top">
        td>
    tr>
table>

Make sense? I just made sure to create a span for each field that I wanted to display in my custom layout.

Oh, and here’s a quick tip at no extra charge. If you don’t want a field to show up in your form, just don’t create a span for it. No error will be thrown (unless it’s a required field) and the form will still save and update just fine.

  • is this hillbilly forms and css, js, FREE / open source library?, can i use it for my customer for a prod.environment ? – userAZLogicApps Oct 21 '18 at 14:19
1

If you are using a custom form you can use the client side people picker control https://msdn.microsoft.com/en-us/library/office/jj713593.aspx

The picker and its functionality are defined in the clientforms.js, clientpeoplepicker.js, and autofill.js script files, which are located in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPLATE\LAYOUTS folder on the server.

HTML

<!-- 
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
    <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" />
    <div id="peoplePickerDiv"></div>
    <div>
        <br/>
        <input type="button" value="Get User Info" onclick="getUserInfo()"></input>
        <br/>
        <h1>User info:</h1>
        <p id="resolvedUsers"></p>
        <h1>User keys:</h1>
        <p id="userKeys"></p> 
        <h1>User ID:</h1>
        <p id="userId"></p>
    </div>
</asp:Content>
-->

JavaScript

// Run your custom code when the DOM is ready.
$(document).ready(function () {

    // Specify the unique ID of the DOM element where the
    // picker will render.
    initializePeoplePicker('peoplePickerDiv');
});

// 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'] = true;
    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() {

    // Get the people picker object from the page.
    var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;

    // Get information about all users.
    var users = peoplePicker.GetAllUserInfo();
    var userInfo = '';
    for (var i = 0; i < users.length; i++) {
        var user = users[i];
        for (var userProperty in user) { 
            userInfo += userProperty + ':  ' + user[userProperty] + '<br>';
        }
    }
    $('#resolvedUsers').html(userInfo);

    // Get user keys.
    var keys = peoplePicker.GetAllUserKeys();
    $('#userKeys').html(keys);

    // Get the first user's ID by using the login name.
    getUserId(users[0].Key);
}

// Get the user ID.
function getUserId(loginName) {
    var context = new SP.ClientContext.get_current();
    this.user = context.get_web().ensureUser(loginName);
    context.load(this.user);
    context.executeQueryAsync(
         Function.createDelegate(null, ensureUserSuccess), 
         Function.createDelegate(null, onFail)
    );
}

function ensureUserSuccess() {
    $('#userId').html(this.user.get_id());
}

function onFail(sender, args) {
    alert('Query failed. Error: ' + args.get_message());
}

If you go that route - you also have to wire up the logic for it to write back to your list.

  • Where do these things go? And how would we write back to our list? – Rothrock Nov 4 '15 at 18:28
  • It goes in your custom form page, where you want it to show up. you would need to create with CSOM or JavaScript event to write back to the list. I've used this in pure customer pages - but have not tried to integrate with page that has server side controls. – Jesus Shelby Nov 4 '15 at 18:48
  • I think Mr. Rackley included this in his most recent build of Forms-7. – bgmCoder Nov 12 '15 at 20:44
  • @bgmCoder, is the forms-7 free , open source product? can i implement his code for my prod.enviornment? – userAZLogicApps Oct 21 '18 at 14:21
  • It used to be free. It has been a few years now, I don't know the state of the project anymore. – bgmCoder Oct 22 '18 at 19:13
1

I have never used infopath till now but I suggest you try to use CSR Form with JavaScript.

With that you are able to rebuild the whole form from scratch with everything you need.

The code examples I show here are from the following example. https://code.msdn.microsoft.com/office/CSR-code-samples-11-Fully-54ebcaa6

I just copy the steps and code here in case the link becomes invalid.

Deployment steps:

  1. Create a Custom list
  2. Add some columns to the list (like in the code example).
  3. Upload the yourJSfile.js file to the document library
  4. Edit list form page
  5. Go to list view web-part properties and add the JSLink fill (~sitecollection/StyleLibrary/JSLink-Samples/FullyCustomizedForm.js) to JS link property under the Miscellaneous Tab.
  6. Change form template name to CSRListForm
    Change form template name to CSRListForm
  7. Click apply button then stop page editing.

    (function () { 
    
    // Create object that have the context information about the field that we want to change it's output render  
    
    var formTemplate = {};
    formTemplate.Templates = {};
    formTemplate.Templates.View = viewTemplate;
    
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(formTemplate);
    
    })(); 
    
    // This function provides the rendering logic for the Custom Form
    function viewTemplate(ctx) {
    
    var formTable = "".concat("<table width='100%' cellpadding='5'>",
                                    "<tr>",
                                        "<td><div>Title</div></td>",
                                        "<td><div>{{TitleCtrl}}</div></td>",
                                        "<td><div>Date</div></td>",
                                        "<td><div>{{DateCtrl}}</div></td>",
                                    "</tr>",
                                    "<tr>",
                                        "<td><div>Category</div></td>",
                                            "<td><div>{{CategoryCtrl}}</div></td>",
                                        "<td><div>Active</div></td>",
                                        "<td><div>{{ActiveCtrl}}</div></td>",
                                    "</tr>",
                                    "<tr>",
                                        "<td></td>",
                                        "<td><input type='button' value='Save' onclick=\"SPClientForms.ClientFormManager.SubmitClientForm('{{FormId}}')\" style='margin-left:0' ></td>",
                                    "</tr>",
                              "</table>");
    
    
    //Replace the tokens with the default sharepoint controls
    formTable = formTable.replace("{{TitleCtrl}}", getSPFieldRender(ctx, "Title"));
    formTable = formTable.replace("{{DateCtrl}}", getSPFieldRender(ctx, "Date"));
    formTable = formTable.replace("{{CategoryCtrl}}", getSPFieldRender(ctx, "Category"));
    formTable = formTable.replace("{{ActiveCtrl}}", getSPFieldRender(ctx, "Active"));
    formTable = formTable.replace("{{FormId}}", ctx.FormUniqueId);
    
    return formTable;
    }
    
    //This function code set the required properties and call the OOTB (default) function that use to render Sharepoint Fields 
    function getSPFieldRender(ctx, fieldName)
    {
    var fieldContext = ctx;
    
    //Get the filed Schema
    var result = ctx.ListSchema.Field.filter(function( obj ) {
        return obj.Name == fieldName;
    });
    
    //Set the field Schema  & default value
    fieldContext.CurrentFieldSchema = result[0];
    fieldContext.CurrentFieldValue = ctx.ListData.Items[0][fieldName];
    
    //Call  OOTB field render function 
    return ctx.Templates.Fields[fieldName](fieldContext);
    }
    

And finally if you want to use the people picker then have a look on another question here:

Get the ID and Name from multiple Client side People pickers to store in a list

or another articleon CSR forms: http://www.codeproject.com/Articles/888923/SharePoint-Client-Side-Rendering-List-Forms-p

I also suggest to have a look into Nintex Forms to publish custom list forms on SharePoint 2013.

  • All this seems to do is remove the labels and break my form. I can't get save or cancel buttons and the ones in the ribbon are even broken. – Rothrock Nov 4 '15 at 18:19
  • Did you check if the code is correct? I just copied it from the link I gave. Of course you still need to check if the JavaScript is correct. @Rothrock I guess you are not a developer? The approach I gave definetley needs a developer. Without understanding the code you can easily run into problems you can hardly fix it by yourself. – Sebastian Schütze Nov 5 '15 at 6:41
  • I downloaded the code from the source. It doesn't create any errors in the debugger. I have quite a bit of experience in web development and client side scripting. But without documentation or explanation from the source it is very hard to figure out what something like ctx.Templates.Fields[fieldName](fieldContext) [or any of the SP API code] should be doing or where it might be going wrong. The source you've linked to doesn't include any documentation. – Rothrock Nov 5 '15 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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