Contact Us
Please fill out the form below and we will get in touch within four business hours.

*
*
*
*
*
*
*Interested In:
(Check all that apply)



 
 
Synergy Corporate Technologies
Synergyonline > Blog > Posts > Building an Interactive Portfolio Gallery using jQuery and SharePoint
January 26

Building an Interactive Portfolio Gallery using jQuery and SharePoint

In this post I will describe in detail how to build a nice interactive portfolio gallery using a SharePoint List as a datasource.

Here’s what the end product looks like:





 

This can be found by visiting our website:  http://www.synergyonline.com/web/Pages/WebPortfolio.aspx

As always I begin with building the list structure to store all the relevant data:





 

Because this list is being used in other areas of our site, there a several unnecessary fields in the list.  The only relevant fields in this example are as follows:

WebsiteThumbnail

Title

WebsiteUrl

CaseStudyUrl

DisplayDescription

PlatformImage

Next we’ll look at the html:

<asp:UpdatePanel ID="upPnlPortfolio" UpdateMode="Conditional" runat="server">
<ContentTemplate>
    <div id="portfolio-container">
        <div id="portfolio-left">
            <div id="portfolio-companies">
                <ul>
                    <asp:Repeater ID="rptCompanies" runat="server" Visible="true" onitemdatabound="rptCompanies_ItemDataBound">
                        <ItemTemplate>
                            <li><asp:Image ID="imgThumbnail" Width="121px" runat="server" /></li>
                        </ItemTemplate>
                    </asp:Repeater>
                </ul>
            </div>
        </div>
        <div id="portfolio-right">
                <asp:Repeater ID="rptThumbnails" runat="server" Visible="true" onitemdatabound="rptThumbnails_ItemDataBound">
                    <ItemTemplate>
                        <div class="portfolio-right-content">
                            <div class="portfolio-thumbnail">
                                <asp:Image ID="imgThumbnail" runat="server" />
                            </div>
                            <div class="portfolio-description">
                                    <p class="portfolio-description-header">
                                        <asp:Literal ID="ltClientName" runat="server"></asp:Literal>
                                    </p>
                                    <p class="portfolio-description-text">
                                        <asp:Literal ID="ltDescription" runat="server"></asp:Literal>
                                        <br /><br />
                                        <asp:Literal ID="ltWebsiteLink" runat="server"></asp:Literal>
                                    </p>
                            </div>
                            <div class="portfolio-platform">
                                <asp:Literal ID="ltPlatformImage" runat="server"></asp:Literal>
                            </div>
                            <div class="dvLearnMoreImage"><asp:Literal ID="imgLearnMore" runat="server"></asp:Literal></div>
                        </div>
                    </ItemTemplate>
                </asp:Repeater>
            <br clear="all" />
        </div>
    </div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Label ID="lblMessage" Text="" runat="server"></asp:Label>
 
<script type="text/javascript" src="/Style%20Library/js/synergy-ourportfolio.js"></script>

As you can see, there are 2 ASP.Net Repeaters being used.  Once the data is retrieved from the SharePoint List, the data is bound to both repeaters, each picking out the data it needs to display (the webpart code will be provided at the end of this article).

The CSS applied to the html is as follows:

#portfolio-container {width: 100%; height: 100%;}    
    #portfolio-left {width: 170px; float: left; border-right: solid 1px #777;}
        #portfolio-companies {width: 155px;}
        #portfolio-companies ul {padding: 0;}
        #portfolio-companies ul li {list-style: none; font-family: Arial, Helvetica, sans-serif; font-size: 12px; padding-left: 30px; margin-bottom: 20px; line-height: 77px; height: 77px; vertical-align: middle;}
        #portfolio-companies ul li.liWebSelected:hover {cursor: pointer; background-image: url(/SiteCollectionImages/portfolio/img_port_dot.png); background-position: left center; background-repeat: no-repeat;}
        #portfolio-companies ul li.liSPSolSelected:hover {cursor: pointer; background-image: url(/SiteCollectionImages/portfolio/img_orange_dot.png); background-position: left center; background-repeat: no-repeat;}
        #portfolio-companies ul li.liTechSelected:hover {cursor: pointer; background-image: url(/SiteCollectionImages/portfolio/img_blue_dot.png); background-position: left center; background-repeat: no-repeat;}
        #portfolio-companies ul li.liAboutSelected:hover {cursor: pointer; background-image: url(/SiteCollectionImages/portfolio/img_purple_dot.png); background-position: left center; background-repeat: no-repeat;}
        #portfolio-companies ul li.liPreviewSelected:hover {cursor: pointer; background-image: url(/SiteCollectionImages/portfolio/img_gray_dot.png); background-position: left center; background-repeat: no-repeat;}
        #portfolio-companies ul li img 
        {
            vertical-align: middle;
            text-align: center;
            -moz-box-shadow: 0 0 3px 3px #c3c3c3;
            -webkit-box-shadow: 0 0 3px 3px #c3c3c3;
            box-shadow: 0 0 3px 3px #c3c3c3;
            filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=3, OffY=3, Color='#c3c3c3', Positive='true');    
        }
 
        .liWebSelected {background-image: url(/SiteCollectionImages/portfolio/img_port_dot.png); background-position: left center; background-repeat: no-repeat;}
        .liSPSolSelected {background-image: url(/SiteCollectionImages/portfolio/img_orange_dot.png); background-position: left center; background-repeat: no-repeat;}
        .liTechSelected {background-image: url(/SiteCollectionImages/portfolio/img_blue_dot.png); background-position: left center; background-repeat: no-repeat;}
        .liAboutSelected {background-image: url(/SiteCollectionImages/portfolio/img_purple_dot.png); background-position: left center; background-repeat: no-repeat;}
        .liPreviewSelected {background-image: url(/SiteCollectionImages/portfolio/img_gray_dot.png); background-position: left center; background-repeat: no-repeat;}
 
    #portfolio-right {width: 624px; height: 585px; float: left; text-align: center; vertical-align: middle; position: relative;}
        .portfolio-right-content {display: none; width: 624px; height: 585px; position: absolute; top: 0; left: 0;}
        .portfolio-thumbnail {width: 624px; height: 375px;}
        .portfolio-thumbnail img 
        {
            text-align: center;
            -moz-box-shadow: 0 0 3px 3px #c3c3c3;
            -webkit-box-shadow: 0 0 3px 3px #c3c3c3;
            box-shadow: 0 0 3px 3px #c3c3c3;
            filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=3, OffY=3, Color='#c3c3c3', Positive='true');    
        }
        .portfolio-description {width: 545px; text-align: left; margin-left: 40px;}
            .portfolio-description-header { font-family: Humanist521BT-Light; font-size: 24px; line-height: 24px; margin-bottom: 5px;}
            .portfolio-description-text {line-height: 22px;}
            .portfolio-description-text a:hover {line-height: 20px; color: #176fcc; text-decoration: none; cursor: pointer;}
            .portfolio-description-text a:visited {line-height: 20px; color: #176fcc; text-decoration: none; cursor: pointer;}
            .portfolio-description-text a {line-height: 20px; color: #176fcc; text-decoration: none; cursor: pointer;}
        .portfolio-platform {width: 550px; margin-left: 40px; text-align: right;}

In the main large content area, there are absolutely positioned containers that stack on top of each other.  Whenever you roll over a small thumbnail in the left panel, the appropriate container content displays as a block.  The connection between the two is the index of the item rolled over.  If the 2nd item is rolled over, then the index would be “1” (zero based).  Then I can then display the content panel with index of “1”.  Easy enough, right?

Now for the jQuery “magic”:

$(document).ready(function(){
    // Set first item
    $('#portfolio-companies ul li:eq(0)').addClass(liSelected);
    $('.portfolio-right-content:eq(0)').css('display', 'block');
    
    $('#portfolio-companies ul li').hover(
        function()
        {
            var idx = $('#portfolio-companies ul li').index(this);
            //alert(idx);
            if (idx >= 0)
            {
                $('#portfolio-companies ul li:not(:eq(' + idx+ '))').removeClass(liSelected);
                $('#portfolio-companies ul li:eq(' + idx+ ')').addClass(liSelected);
 
                $('.portfolio-right-content:not(:eq(' + idx+ '))').css('display', 'none');
                $('.portfolio-right-content:eq(' + idx+ ')').css('display', 'block');
            }
        }
    );
 
    // Scroll Portfolio
    var scrollingDiv = $(".portfolio-right-content");
    if (scrollingDiv.length > 0)
    {
        $('#container').scroll(function()
        {
            //alert($('#container').scrollTop());
            if ($('#container').scrollTop() > 270 && $('#container').scrollTop() < 425)
            {
                scrollingDiv
                    .stop()
                    .animate({"marginTop": (($('#container').scrollTop() - 270) + 25) + "px"}, "slow" );            
            }
 
            if ($('#container').scrollTop() <= 270)
                scrollingDiv
                    .stop()
                    .animate({"marginTop": "0px"}, "slow" );
        });
    }    
 
});
 
 
 

The “hover” event is applied to each unordered list item in the left panel.  There is no event that runs when the user rolls off the item, which creates a nice “sticky” effect and allows the user to then click links in the main content area.

There is an additional feature with this page.  If there happens to be a large number of items displayed in the left panel (i.e. small thumbnail area), we wanted the main content area to always remain in the visible area.  Referring to the jQuery code above, you’ll notice that there is a “scroll” event attached to the parent container.  This code essentially says that if the user scrolls past pixel 270 but  not past pixel 425 on the screen, animate the “scrollingDiv” container down or up by adding a certain amount of top margin.

I hope this example of a portfolio gallery gives you great ideas that you can add into your own gallery.  If you’d like the full code for this webpart, css, and js, you can download it here.

Comments

Do I need Visual Studio for this?

This is a great feature I would like to use on my SP Foundation site.  I don't have access to install Web Part Solutions on the server though.
Can this be used via SP Designer? Or do I need to create a WSP using Visual Studio and install to the server?
 on 7/5/2012 12:40 AM

Re:  Do I need Visual Studio for this?

You'll need to create a wsp and install it on the server.  If you are using SharePoint Online, then you can simply upload the wsp to the Solutions Gallery and activate it.

Tyler
 on 7/5/2012 10:00 AM

No WSP File provided

The download link above doesn't have the WSP file, it's a ZIP file that contains individual Visual Studio Project files.

Can you please provide the WSP file so I can upload it to my Solutions Gallery as a Sandbox Solution?

Thanks.
 on 7/17/2012 10:20 PM

Re:  No WSP File provided

This webpart was built along side many others in the solution, so there is not a single WSP containing this webpart.  I provided all the necessary elements, though, so that you can then build and create your own WSP.
 on 7/18/2012 2:28 PM

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Title


Body *


Captcha

 

Attachments


United States
55 Greens Farms Road
Westport, CT 06880
 
1050 Bishop St.
Suite 176
Honolulu, HI 96813
United Kingdom
Unit 13 Elder Way Waterside Drive Langley Berkshire SL3 6EP
United Kingdom
Singapore
Level 37
Ocean Financial Centre
10 Collyer Quay
Singapore 049315
Asia Pacific
Level 6
115 Pitt Street
Sydney NSW 2000
Australia 
+1800-930-4771
+44 (0)1753 541 000
+(65) 6232 2329
+61 2 9113 7243
United States
United Kingdom
Singapore
Australia
This web page conforms to W3C's "Web Content Accessibility Guidelines 1.0" Level "A" © 2014 Synergy Corporate Technologies
This site is best viewed in IE8 or above. Some features may not render properly if you are using an older browser.