Image gallery from attachments in tooltips

Do you want to obtain a small image gallery display in a tooltip based on a files attached to an item?

Not too complicated to obtain this. We just need JavaScript tooltipster and DataTable library and CSS files. But first let’s build the code for getting attachments based on item id.


Shp.Lists = function () {
            throw 'Cannot instantiate Shp.Lists static class';

 Shp.Lists.GetAttachments = function (listName, itemId, webUrl, success, fail) {
            /// <summary>Get attachments for an item</summary>
            /// <param name="listName" type="String" optional="false" mayBeNull="false">List name</param>
            /// <param name="itemId" type="Number" integer="true" optional="false" mayBeNull="false">List item</param>
            /// <param name="success" type="Function" optional="false" mayBeNull="false">Success</param>
            /// <param name="fail" type="Function" optional="true" mayBeNull="false">Fail</param>
            var e = Function.validateParameters(arguments, [{ name: 'listName', type: String, mayBeNull: false, optional: false },
                                                            { name: 'itemId', type: Number, integer: true, mayBeNull: false, optional: false },
                                                            { name: 'webUrl', type: String, mayBeNull: true, optional: false },
                                                            { name: 'success', type: Function, mayBeNull: false, optional: false },
                                                            { name: 'fail', type: Function, mayBeNull: false, optional: true }], true);
            if (e) throw 'Shp.Lists.GetAttachments was called with invalid parameters. ' + e;
            var fail = fail || (function (err) { alert(err); });
            var ctx = (webUrl === null) ? SP.ClientContext.get_current() : new SP.ClientContext(webUrl);

            Shp.Lists._GetAttachments(listName, itemId, ctx, success, fail);

     Shp.Lists._GetAttachments = function (listName, itemId, ctx, success, fail) {
            var oList = ctx.get_web().get_lists().getByTitle(listName);
            var oListItem = oList.getItemById(itemId);
            var files = oListItem.get_attachmentFiles();

            ctx.executeQueryAsync(function () {
                var results = [];
                for (var i = 0; i < files.get_count() ; i++) {
                    var file = files.itemAt(i);
                    results.push({ 'fileName': file.get_fileName(), 'serverRelativeUrl': file.get_serverRelativeUrl() });
            }, function (sender, args) {


Now, let have a look in XSLT code. We need it to display the data.

<xsl:stylesheet version="1.0" xmlns:xsl=""
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
    <xsl:output method="html" indent="yes"/>
    <xsl:template match="/">

      <div class="card-body">
          <table class="table table-striped table-bordered nowrap" id="dataTable" width="100%" cellspacing="0">
                <th>Product<br />Name</th>
                <th>Product<br />Code</th>
                <th>Available<br />Qty</th>
              <xsl:for-each select="/dsQueryResponse/Rows/Row">
                    <a title="Loading..." class="product-images" data-id="{@ID}">
                      <xsl:value-of select="@ID" disable-output-escaping="yes" />
                    <xsl:value-of select="@ProductName" disable-output-escaping="yes" />
                    <xsl:value-of select="@ProductCode" disable-output-escaping="yes" />
                    <xsl:value-of select="@ProductDescription" disable-output-escaping="yes" />
                    <xsl:value-of select="@CountryCode" disable-output-escaping="yes" />
                    <xsl:value-of select="@Supplier" disable-output-escaping="yes" />
                    <xsl:value-of select="@Qty" disable-output-escaping="yes" />
                    <xsl:value-of select="@Currency" disable-output-escaping="yes" />
                    <xsl:value-of select="@Price" disable-output-escaping="yes" />


Our scope is to display a small image gallery in a toolip when we click in a link. So, for this, we need to run the following code when page loads.

        scrollX: true,
        paging: false,
        fixedColumns: {
            leftColumns: 1
        'aoColumnDefs': [
            { "bSortable": false, "aTargets": [0] }

        'drawCallback': function (settings) {
                trigger: 'click',
                contentAsHTML: true,
                interactive: true,
                theme: 'tooltipster-shadow',
                functionBefore: function (instance, helper) {
                    var $origin = jQuery(helper.origin);
                    var poId = $origin.attr('data-id');
                    if (Boolean($'loaded')) !== true) {
                        Shp.Lists.GetAttachments('Products list name', parseInt(poId), null, function (attachments) {
                            if (attachments.length === 0) {
                                instance.content('No image found');
                                $'loaded', true);

                            var html = '';
                            for (var k = 0; k < attachments.length; k++) {
                                html += '<div class="mySlides">' +
                                    '<img src="' + attachments[k].serverRelativeUrl + '" style="width:100px; height: 100px">' +
                            instance.content('<div class="slideshow-container">' + html + '</div>');

                            function (err) {
                                instance.content('Cannot get images:' + err);
                                $'loaded', true);

Of course we can apply different style on the gallery, but this is not the scope here. This is just to give you a start from where to start.