0

I am using the modern PnP SPFx people search web part - and for the people search below is the out of the box template is generated by the web part:

<content id="template">

    <style>
        #pnp-modern-search_{{@root.instanceId}} .personaCard {
            margin: 10px;
        }
    </style>

    <div id="pnp-modern-search_{{@root.instanceId}}" class="template_root">
        {{#if @root.hasPrimaryOrSecondaryResults}} 
            <div class="template_defaultCard">
                {{#if showResultsCount}}
                <div class="template_resultCount">
                    <label class="ms-fontWeight-semibold">{{getCountMessage @root.paging.totalItemsCount keywords}}</label>
                </div>
                {{/if}}
                <div class="ms-Grid">
                    <div class="ms-Grid-row">
                        {{#each items as |item|}}
                        <div class="ms-Grid-col ms-sm12 ms-md12 ms-lg12">
                            {{#> resultTypes item=item}}
                                <div class="personaCard">
                                    {{#with (split AccountName '|')}}
                                        <pnp-persona-card fields-configuration="{{JSONstringify ../../../peopleFields}}" item="{{JSONstringify item}}" persona-size="{{../../../personaSize}}" />
                                    {{/with}}
                                </div>
                            {{/resultTypes}}
                        </div>
                        {{/each}}
                    </div>
                </div>
            </div>
            {{#if @root.paging.showPaging}}
                <pnp-pagination 
                    total-items="{{@root.paging.totalItemsCount}}" 
                    hide-first-last-pages="{{@root.paging.hideFirstLastPages}}"
                    hide-disabled="{{@root.paging.hideDisabled}}"
                    hide-navigation="{{@root.paging.hideNavigation}}"
                    range="{{@root.paging.pagingRange}}" 
                    items-count-per-page="{{@root.paging.itemsCountPerPage}}" 
                    current-page-number="{{@root.paging.currentPageNumber}}"
                >
                </pnp-pagination>
            {{/if}}
        {{else}}
            {{#unless showBlank}}
                <div class="template_noResults">{{@root.strings.NoResultMessage}}</div>
            {{/unless }}
        {{/if}}
    </div>
</content>       
<content id="placeholder">   
    <div id="pnp-modern-search_{{@root.instanceId}}" class="placeholder_root">
        <div class="template_defaultCard">
            {{#if showResultsCount}}
                <div class="template_resultCount">
                    <span class="shimmer line" style="width: 20%"></span>
                </div>
            {{/if}}
            <div class="ms-Grid"> 
                <div class="ms-Grid-row">
                    {{#times @root.paging.totalItemsCount}}
                        <div class="ms-Grid-col ms-sm12 ms-md12 ms-lg12">
                            <pnp-persona-card-shimmers persona-size="{{@root.personaSize}}"></pnp-persona-card-shimmers>
                        </div>
                    {{/times}}
                </div>
            </div>
        </div>
    </div>
</content>

As I understand the below line is displaying the people search related data:

<pnp-persona-card fields-configuration="{{JSONstringify ../../../peopleFields}}" item="{{JSONstringify item}}" persona-size="{{../../../personaSize}}" />

The above code is giving very limited result with just user full name and email:

People Search Template Result

My question is - how can we add additional user properties to the above template like - Department, UserPhone, CellPhone, Manager, AboutMe, HomePhone, Office, etc. ?

The above property I could able to configure through the manage property configuration pane - however, my intention here is to handle this through the handlebar customization because I have some scenarios, where I need to display the value conditionally, so, if someone can add a sample if condition with some values like - HomePhone, Office, etc, to this exiting handlebar template would be a great help.

3 Answers 3

1

If you want to apply more conditions in the template, you use Handlebars. Basically you use the managed properties values inside curly braces: {{}} inside the template.

Example 1:

  {{#unless WorkEmail}} 
     <p>if there is no work email, render this</p>
  {{/unless}}

In this example, if there's no work email, render the paragraph. This is handlebars way of having "If null" or !

Example 2

  {{#if WorkEmail}} 
      <p>This paragraph will render only if the managed property has a truthy value</p>
  {{/if}}

This example uses if condition.

Note in these examples am just using the WorkEmail managed property, but you can choose other managed properties the same way. The web part uses handlebars built it helpers (the if and unless). If you want to create your own helpers for example to check if the managed property equals a specific value (not just true/false checks), then it's not supported by this version of the modern search webparts and you'll need to upgrade to the newer one to have custom helpers (which isn't free): https://www.aequos.ca/features

2

Okay lets say you would have a card style layout go to your search webpart settings - on page 2 of the settings enter following values into Selected Properties

Title,Path,Created,Filename,SiteLogo,PreviewUrl,PictureThumbnailURL,ServerRedirectedPreviewURL,ServerRedirectedURL,HitHighlightedSummary,FileType,contentclass,ServerRedirectedEmbedURL,DefaultEncodingURL,owstaxidmetadataalltagsinfo,Author,AuthorOWSUSER,SPSiteUrl,SiteTitle,IsContainer,IsListItem,HtmlFileType,SiteId,WebId,UniqueID,NormSiteID,NormListID,NormUniqueID,Rank,AccountName,FirstName,LastName,Department,WorkPhone,WorkEmail,PictureURL,SOSDescription,EndDateOWSDATE,EventDateOWSDATE,ContentSource,JobTitle,Location,EditorOWSUSER,ModifiedBy,Description,ModifiedOWSDATE,ContentType,OriginalPath,FileExtension,ParentLink,PromotedState,PromotedStateOWSNMBR,IsDocument,NormWebID

On page 3 of the search webpart settings select the "Results layout"

Custom

Then edit the template and put following template for card layout into the editor box

    <content id="template">

    <style>
    /* Insert your CSS overrides here */
    #pnp-modern-search_{{@root.instanceId}} {
    /* Insert your CSS overrides here */
    }
    
    .livepersona-themePrimary a {
        color: {{ @root.themeVariant.palette.themePrimary }};
    }           

    .livepersona-card-item, 
    .template_livepersona-card {
        margin-right: 15px;
        -webkit-box-flex: 0;
        -ms-flex: 0 0 345px;
        flex: 0 0 345px;
    }
    .livepersona-info {
        color: {{@root.themeVariant.palette.neutralPrimary}};
    }
    .live-persona-card {
        background-color: {{@root.themeVariant.palette.white}}; 
        border: 1px solid {{@root.themeVariant.palette.neutralLight}};
        box-sizing: border-box;
        max-width: 320px;
        min-width: 206px;
        position: relative;
        margin-bottom: 15px;
        user-select: none;
    }
    .live-persona-card:hover {
        cursor: pointer;
        border-color: {{@root.themeVariant.palette.neutralTertiaryAlt}} !important;
    }
    .livepersona-card-headercontainer {
        border-bottom: 1px solid {{@root.themeVariant.palette.neutralLight}};
        position: relative;
        background-color: {{@root.themeVariant.palette.white}};
        overflow: hidden;
    }
    [dir="ltr"] .livepersona-ContainerCard-title {
        text-align: left;
    }
    .livepersona-ContainerCard-title {
        font-size: 17px;
        font-weight: 300;
        font-weight: 400;
        width: 100%;
        line-height: 17px;
        margin-top: 30px;
        padding: 0 12px;
        color: {{@root.themeVariant.palette.themePrimary}};       
        -webkit-animation-name: ms-fadeIn;
        animation-name: ms-fadeIn;
        -webkit-animation-duration: 267ms;
        animation-duration: 267ms;
        -webkit-animation-timing-function: cubic-bezier(.1,.9,.2,1);
        animation-timing-function: cubic-bezier(.1,.9,.2,1);
        -webkit-animation-delay: 50ms;
        animation-delay: 50ms;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
    }
    .livepersona-ContainerCard-subTitle {
        padding: 0px 12px;
        font-size: 14px;
        font-weight: 400;
        padding-top: 5px;
        color: {{@root.themeVariant.palette.neutralPrimary}};
        -webkit-animation-name: ms-fadeIn;
        animation-name: ms-fadeIn;
        -webkit-animation-duration: 167ms;
        animation-duration: 167ms;
        -webkit-animation-timing-function: cubic-bezier(.1,.9,.2,1);
        animation-timing-function: cubic-bezier(.1,.9,.2,1);
        -webkit-animation-delay: .25s;
        animation-delay: .25s;
    }
    .livepersona-ContainerCard-subTitle strong, .livepersona-ContainerCard-subTitle b
    {
        color: {{@root.themeVariant.palette.themePrimary}};
    }
    .livepersona-card-header-normal {
        border-bottom: 2px solid {{@root.themeVariant.palette.neutralLight}};
    }
    .livepersona-card-header-normal {
        position: relative;
        width: 100%;
        padding-top: 0px;
        height: auto;
        cursor: pointer;
        background-color: {{@root.themeVariant.palette.white}};
        display: block;
    }
    .livepersona-card-titletopfix {
        margin-top: 10px;
    }
    .livepersona-margin-10px {
        margin: 10px
    }
    .livepersona-image {
        font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, "Roboto", "Helvetica Neue", sans-serif;
        font-size: 14px;
        font-weight: 400;
        overflow: hidden;
        animation-duration: 0.367s;
        animation-timing-function: cubic-bezier(0.1, 0.25, 0.75, 0.9);
        margin-right: 10px;
        top: 0px;
        left: 0px;
        width: 100px;
        height: 100px;
        border: 0px none;
        border-radius: 50%;
        perspective: 1px;
    }

    .livepersona-image img {
        display: block;
        opacity: 1;
        width: 100%;
        height: 100%;
        object-fit: cover;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }

    .livepersona-flex-container {
        display: -ms-flexbox;
        display: -webkit-flex;
        display: flex;
        -webkit-flex-direction: row;
        -ms-flex-direction: row;
        flex-direction: row;
        -webkit-flex-wrap: nowrap;
        -ms-flex-wrap: nowrap;
        flex-wrap: nowrap;
        -webkit-justify-content: flex-start;
        -ms-flex-pack: start;
        justify-content: flex-start;
        -webkit-align-content: stretch;
        -ms-flex-line-pack: stretch;
        align-content: stretch;
        -webkit-align-items: flex-start;
        -ms-flex-align: start;
        align-items: flex-start;
    }

    .livepersona-flex-item:nth-child(1) {
        -webkit-order: 0;
        -ms-flex-order: 0;
        order: 0;
        -webkit-flex: 0 1 auto;
        -ms-flex: 0 1 auto;
        flex: 0 1 auto;
        -webkit-align-self: stretch;
        -ms-flex-item-align: stretch;
        align-self: stretch;
    }

    .livepersona-flex-item:nth-child(2) {
        -webkit-order: 0;
        -ms-flex-order: 0;
        order: 0;
        -webkit-flex: 1 1 auto;
        -ms-flex: 1 1 auto;
        flex: 1 1 auto;
        -webkit-align-self: stretch;
        -ms-flex-item-align: stretch;
        align-self: stretch;
    }

    .livepersona-primaryText {
        white-space: nowrap;
        color: {{ @root.themeVariant.palette.neutralPrimary }};
        font-weight: 300;
        font-size: 21px;
    }
    </style>




    <div class="template_root">
        {{#if @root.hasPrimaryOrSecondaryResults}} 
            <div class="template_defaultCard">
                {{#if showResultsCount}}
                <div class="template_resultCount">
                    <label class="ms-fontWeight-semibold">{{getCountMessage @root.paging.totalItemsCount keywords}}</label>
                </div>
                {{/if}}
                <div class="document-card-container">
                    {{#each items as |item|}}
                    <div class="document-card-item">
                        {{#> resultTypes item=item}}
                            {{!-- The block below will be used as default item template if no result types matched --}}
                            {{#eq item.contentclass 'STS_ListItem_851'}}
                                <pnp-video-card data-item="{{JSONstringify item}}" data-fields-configuration="{{JSONstringify @root.documentCardFields}}" data-enable-preview="{{@root.enablePreview}}" data-show-file-icon="{{@root.showFileIcon}}" data-is-compact="{{@root.isCompact}}"></pnp-video-card>
                            {{else}}
                                <pnp-document-card data-item="{{JSONstringify item}}" data-fields-configuration="{{JSONstringify @root.documentCardFields}}" data-enable-preview="{{@root.enablePreview}}" data-show-file-icon="{{@root.showFileIcon}}" data-is-compact="{{@root.isCompact}}"></pnp-document-card>
                            {{/eq}} 
                        {{/resultTypes}}
                    </div>
                    {{/each}}
                </div>
            </div>
            {{#if @root.paging.showPaging}}
                <pnp-pagination 
                    data-total-items="{{@root.paging.totalItemsCount}}" 
                    data-hide-first-last-pages="{{@root.paging.hideFirstLastPages}}"
                    data-hide-disabled="{{@root.paging.hideDisabled}}"
                    data-hide-navigation="{{@root.paging.hideNavigation}}"
                    data-range="{{@root.paging.pagingRange}}" 
                    data-items-count-per-page="{{@root.paging.itemsCountPerPage}}" 
                    data-current-page-number="{{@root.paging.currentPageNumber}}"
                >
                </pnp-pagination>
            {{/if}}
        {{else}}
            {{#unless showBlank}}
                <div class="template_noResults">{{@root.strings.NoResultMessage}}</div>
            {{/unless}}
        {{/if}}
    </div>
</content>

<content id="placeholder">   
    <div class="placeholder_root">
        <div class="template_defaultCard">
            {{#if showResultsCount}}
                <div class="template_resultCount">
                    <span class="shimmer line" style="width: 20%"></span>
                </div>
            {{/if}}
            <div class="document-card-container"> 
                {{#times @root.paging.totalItemsCount}}
                    <div class="document-card-item">
                        <pnp-document-card-shimmers data-is-compact="{{@root.isCompact}}"></pnp-document-card-shimmers>
                    </div>
                {{/times}}
            </div>
        </div>
    </div>
</content>

then configure the "Result Types" by clicking on the "Edit Result Types" button Add a new row and enter following values

Managed Property = contentclass
Operator = Contains
Condition Value = SPSPeople

And in the "Inline template" editor box enter following code

    <div class="template_livepersona-card">

    <div class="livepersona-card-item">

        <div>
            <div tabindex="0" data-is-focusable="true" role="button"
                class="ms-DocumentCard ms-DocumentCard--actionable live-persona-card">

                {{#with (split AccountName '|')}}
                <div style="position: relative; height: 100%;">

                    <div aria-label="{{../FirstName}} {{../LastName}}" class="livepersona-card-header-normal"
                        data-focusable-context="ActivityCards" data-is-focusable="true" data-interception="propagate"
                        data-nested-context="Card" data-sp-sitetype-hint="Comm" 
                        title="{{../FirstName}} {{../LastName}}" tabindex="-1">

                        <div title="{{../FirstName}} {{../LastName}}">

                        <div class="ms-DocumentCardPreview livepersona-card-headercontainer">
                            <div class="livepersona-flex-container">
                                <div class="livepersona-flex-item ms-Persona-coin ms-Persona--size100">
                                    <div class="ms-Persona-imageArea">
                                        <div class="ms-Image ms-Persona-image livepersona-image livepersona-margin-10px" style="width: 100px; height: 100px;">
                                            <pnp-live-persona data-upn="{{[2]}}" data-disableHover="false" data-template="<img class='img-preview ms-Image-image is-loaded ms-Image-image--cover ms-Image-image--landscape is-fadeIn' src='/_layouts/15/userphoto.aspx?size=L&username={{[2]}}'' alt=''/>" />
                                        </div>
                                    </div>
                                </div>
                                <div class="livepersona-flex-item">
                                    <div class="livepersona-primaryText livepersona-themePrimary livepersona-margin-10px">
                                        <a target="_blank" data-interception="off" 
                                            href="https://delve.office.com/?q={{../FirstName}}+{{../LastName}}&searchpage=1&searchview=people&v=search"
                                            >
                                            <pnp-live-persona data-upn="{{[2]}}" data-disableHover="false" data-template="{{../FirstName}} {{../LastName}}" />
                                            </a>
                                            
                                    </div>
                                    <a target="_blank" data-interception="off"  class="livepersona-info"
                                        href="https://delve.office.com/?q={{../FirstName}}+{{../LastName}}&searchpage=1&searchview=people&v=search"
                                        >
                                    <span>
                                    <pnp-live-persona data-upn="{{[2]}}" data-disableHover="false" data-template="
                                        {{#if ../JobTitle}}
                                            <span>
                                                <i class='ms-Icon ms-Icon--Work' aria-hidden='true'></i> {{../JobTitle}}<br />
                                            </span>
                                        {{/if}}
                                        {{#if ../Department}}
                                            <span>
                                                <i class='ms-Icon ms-Icon--Group' aria-hidden='true'></i> {{../Department}}<br />
                                            </span>
                                        {{/if}}" />
                                    </span>
                                    </a>
                                </div>
                            </div>
                        </div>

                            <a aria-label="{{../FirstName}} {{../LastName}}" 
                            data-focusable-context="ActivityCards" data-is-focusable="true"
                            data-nested-context="Card" data-sp-sitetype-hint="Comm" href="{{getUrl item}}"
                            target="_blank" data-interception="off" title="{{../FirstName}} {{../LastName}}" tabindex="-1">
                                <div class="livepersona-ContainerCard-title livepersona-card-titletopfix  ">
                                
                                </div>
                                <div class="livepersona-ContainerCard-subTitle livepersona-themePrimary">
                                        {{#if ../WorkPhone}}
                                            <span class="persona-link ">
                                                <a href="tel:{{replace (replace (replace ../WorkPhone "-" "") "/" "") " " ""}}" title="Telephone">
                                                    <i class="ms-Icon ms-Icon--Phone" aria-hidden="true"></i>&nbsp;
                                                    {{../WorkPhone}}
                                                </a><br />
                                            </span>
                                        {{/if}}
                                        {{#if ../WorkEmail}}
                                            <span class="persona-link ">
                                                <a href="mailto:{{../WorkEmail}}" title="Email">
                                                    <i class="ms-Icon ms-Icon--Mail" aria-hidden="true"></i>&nbsp;
                                                    {{../WorkEmail}}
                                                </a>
                                            </span><br />
                                        {{/if}}
                                            <span class="persona-link ">
                                                <a target="_blank" data-interception="off" href="https://delve.office.com/?q={{../FirstName}}+{{../LastName}}&searchpage=1&searchview=people&v=search" title="Delve">
                                                    <i class="ms-Icon ms-Icon--DelveLogo" aria-hidden="true"></i>&nbsp;
                                                    Find this person in Delve
                                                </a>
                                            </span>
                                </div>
                            </a>
                        </div>
                    </div>
                </div>
                
                {{/with}}
            </div>
        </div>
    </div>           
</div>

That should render some nice persona cards (maybe needs some CSS styling) and when hovering with the mouse over a person the live persona card shows up.

7
  • Thank you so much for this. :-)
    – SP 2022
    Aug 12, 2020 at 5:01
  • I have tried your steps, but I am getting an empty grey color square box, even though the search query is valid....any idea why the rendering does not work?
    – SP 2022
    Aug 12, 2020 at 6:00
  • It renders on web part edit mode but when I save and publish the page, I just see an empty grey color box on a valid people search query....any idea why?
    – SP 2022
    Aug 12, 2020 at 6:08
  • check the "Selected Properties" if you have every thing of the above described properties added Aug 13, 2020 at 7:35
  • I have selected a few properties which have values however it does not render, it is a blank screen. Can you please share a screenshot where you found rendering is working, just wanted to verify what's wrong in my approach.
    – SP 2022
    Aug 18, 2020 at 12:08
0

You have these options out of the box from the property pane itself. enter image description here

enter image description here

3
  • Hi - thanks for your reply - I am aware these options, my intention to handle this through handlebar template because I have some scenarios where I want to conditionally display the manage property through the handlebar customization.
    – SP 2022
    Jun 11, 2020 at 10:57
  • Did you figure this out? I get the "16 results for 'x'" but no actual results....
    – matt
    Jan 14, 2021 at 20:45
  • Wait - now I do get the hover effect, but only on the linked person's name. That works!
    – matt
    Jan 14, 2021 at 20:58

Your Answer

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

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