Thursday, April 24, 2014

Solution to displaying attachments for a list item in a search result

Matthew McDermott has done it again people! He has given me yet another hard problem to solve. This time it’s about getting the number of attachments of a list item in your search results. And as an added bonus, I’m throwing in the attachment links as well (which actually is a side effect).

image

As it turns out there is no managed property named anything related to attachment or count which will return the number of attachments or the attachment links. That is, if you check the TechNet list or view the search schema via the UI.
Topics covered in this post:
  • Debugging using Search Query Tool v2 – with experimental features turn on
  • The undocumented managed property LinkOfficeChild
  • Custom display templates

By now, everyone digging for data related to search should have downloaded SharePoint 2013 Search Query Tool v2 from Codeplex, and you should also have enabled the experimental features as I mention in the release post for the tool.

I started by creating a list, adding an item and finally adding two attachments to the item.

image

Once the item was crawled I fired up the Search Query Tool, searched for OneOne, and clicked the View all properties link for the item.

image

In the properties window I then started scanning for the names of my attachments, and it’s there!!!! There’s an undocumented managed property named LinkOfficeChild which gives us exactly what we need. If you split the value on line break you will get the count. Problem solved!

Steve Curran actually mention this property briefly in an old post from 2009 regarding MOSS search.

image

Below is a sample display template which lists the number of attachments and the attachment links as seen in the screenshot at the top.

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
    <title>Item with attachments</title>

    <!--[if gte mso 9]><xml>
    <mso:CustomDocumentProperties>
    <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
    <mso:MasterPageDescription msdt:dt="string">Viser standardmalen for resultatelementet.</mso:MasterPageDescription>
    <mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
    <mso:TargetControlType msdt:dt="string">;#SearchResults;#</mso:TargetControlType>
    <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
    <mso:ManagedPropertyMapping msdt:dt="string">'Title':'Title','LinkOfficeChild':'LinkOfficeChild'</mso:ManagedPropertyMapping>
    <mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
    <mso:HtmlDesignStatusAndPreview msdt:dt="string">https://techmikael.sharepoint.com/search/_catalogs/masterpage/Display%20Templates/Search/Item_Default_Attachment.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
    </mso:CustomDocumentProperties>
    </xml><![endif]-->
</head>
<body>
    <div id="Item_Default">
        <!--#_
            if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
            var id = ctx.ClientControl.get_nextUniqueId();
            var itemId = id + Srch.U.Ids.item;
            var linkString = ctx.CurrentItem.LinkOfficeChild;
            if($isEmptyString(linkString) == false) {
                var attachmentLinks = linkString.split(/\n+/);
                var numberOfLinks = attachmentLinks.length;
                    var linkMarkup = "";
                    for(var i=0; i<numberOfLinks; i++) {
                        linkMarkup = linkMarkup + "<a href='" + attachmentLinks[i] + "'>" + attachmentLinks[i] + "</a><br />";
                    }
                }
                _#-->
        <div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="DefaultItem" class="ms-srch-item">
            <h3 class="ms-srch-ellipsis">_#= ctx.CurrentItem.Title =#_</h3>
            <div>Attachment Count: _#=numberOfLinks=#_</div>
            <div>Attachment Links: _#=linkMarkup=#_</div>
        </div>
        <!--#_
        }
        _#-->
    </div>
</body>
</html>