Using Nivo slider, knockout.js and SharePoint CSOM to create an announcements Slider

I wanted to create a slider that contains images and items from an announcements in my SharePoint 2010 home page. I started writing my own slider, but realized I was just re-creating the wheel. I ended up finding Nivo Slider. It seemed well supported and clean, so I went with that as my jQuery slider. Let’s dive into the code:

First, here is the HTML code I put on the home page. I just added a CEWP and linked it to a text file in a document library. This is the contents of the text file:

<div class="slider-wrapper theme-default">
    <div id="slider" class="nivoSlider">
        <img src="/PhotoLibrary/cityscape1.jpg" title="#htmlcaption" />
        <img src="/PhotoLibrary/cityscape2.jpg" title="#htmlcaption" />
        <img src="/PhotoLibrary/cityscape3.jpg" title="#htmlcaption" />
        <img src="/PhotoLibrary/cityscape4.jpg" title="#htmlcaption" />
    </div>
    <div id="htmlcaption" class="nivo-html-caption">
	<span data-bind="html: sliderCurrentTitle" style="font-weight:bold;text-decoration:underline;"></span>
	<span data-bind="html: sliderCurrentSummary" ></span>
    </div>
</div>

This interesting parts are lines 9 & 10. I set these two spans to Knockout observable arrays. When the slide changes, I am going to update the contents of these values

And here is the JavaScript document.ready code. Explanation of the code is below the block.

$(document).ready(function () {
    $('#slider').nivoSlider({
        effect: 'sliceDownRight',
        pauseTime: 4000,
        beforeChange: function () {
            VM.sliderNextItem()
        }
    });
ko.applyBindings(VM);
VM.sliderRetrieveAnnouncments();
var VM = new viewModel();
})

Lines 2-8: are the settings for the Nivo Slider.
Line 6: This is the most important part of this part of the code. This calls the function for get the next announcement when the slide changes.
Line 10: This line calls the function that initially loads all the announcements into a JavaScript object.

Here is the code to my Knockout View Model (explanations below):

function viewModel() {
    var self = this;
    self.sliderAnnouncement = function (title, summary) {
        this.title = title;
        this.summary = summary;
    }
    self.sliderAllAnnouncments = ko.observableArray();
    self.sliderCurrentTitle = ko.observable();
    self.sliderCurrentSummary = ko.observable()
    self.sliderCurrentItemIndex = 0
    self.sliderNextItem = function () {
        self.sliderCurrentTitle(self.sliderAllAnnouncments()[self.sliderCurrentItemIndex].title)
        self.sliderCurrentSummary(self.sliderAllAnnouncments()[self.sliderCurrentItemIndex].summary)
        self.sliderCurrentItemIndex++
        if (self.sliderCurrentItemIndex > self.sliderAllAnnouncments().length - 1) {
            self.sliderCurrentItemIndex = 0
        }
    }
    self.sliderRetrieveAnnouncments = function () {
        var clientContext = SP.ClientContext.get_current();
        var oList = clientContext.get_web().get_lists().getByTitle('Announcements');
        var camlQuery = new SP.CamlQuery();
        camlQuery.set_viewXml("<View><Query><Where><And><IsNotNull><FieldRef Name='Title' /></IsNotNull><Gt><FieldRef Name='Expires' /><Value Type='DateTime'><Today/></Value></Gt></And></Where><OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy></Query></View>");
        var collListItem = oList.getItems(camlQuery);
        clientContext.load(collListItem);
        clientContext.executeQueryAsync(
	    	Function.createDelegate(this, function () {
	    	    var listItemInfo = '';
	    	    var listItemEnumerator = collListItem.getEnumerator();
	    	    while (listItemEnumerator.moveNext()) {
	    	        var oListItem = listItemEnumerator.get_current();
	    	        listItemInfo +=
					'\n' + oListItem.get_item('Title') +
			    	'\n' + oListItem.get_item('Summary');
	    	        self.sliderAllAnnouncments.push(new self.sliderAnnouncement(oListItem.get_item('Title'), oListItem.get_item('Summary')));
	    	    }
	    	    self.sliderNextItem()
	    	}),
	    	Function.createDelegate(this, function () { alert('There was an error - sliderRetrieveAnnouncments') }));
    }
}

Lines 3-6 this is the announcement object that I will use to hold the info of a single announcement
Lines 7-9: this is the observable items that are displayed on the slider that contain the announcement’s title and summary
Line 10: this is the index of the current announcement that is being displayed. All I am doing is incrementing it with the NextItem function
Lines 11-18: This is fired when the slide changes (a builtin hook of the Nivo slider). Once it has changed the item, it increments for the next slide.
Lines 19-40: This is the CSOM query to retrieve all the items from the announcement list that have not expired.
Line 23: This is CAML query to get the items that have not expired.
Line 26: This line makes the query.
Lines 30-36: This code loops through the successful returned items.
Line 35: This line puts each of the items into observable array that is used to house all the announcements.

I hope this is helpful to some one. I have been pretty happy with the outcome.

Update: I saw this slider in action at SharePoint conference: http://corporatenewsapp.codeplex.com/
Looked pretty sweet. May have to try to backport to SharePoint 2010.

, ,

4 Responses to Using Nivo slider, knockout.js and SharePoint CSOM to create an announcements Slider

  1. Peng February 15, 2013 at 2:21 pm #

    Hi, Jeff,

    Wow! This is pure awesomeness! The best write-up that I have been looking forward to regarding Knockout, CSOM/REST and Sharepoint.

    Thank you for taking the time to share with us.

    Keep it coming.

    Peng

  2. jbmurphy February 15, 2013 at 2:25 pm #

    Thanks for taking the time to comment. A nice comment is a great way to start the weekend!
    Cheers.

  3. ruud May 12, 2013 at 7:09 am #

    Thanks mate, cannot wait to “play” around with this.

  4. ravi raut May 22, 2014 at 10:46 am #

    I have custom announcement list with title,description column and i want to devlope rotating content query web part based on this list so plz send me XSLT and Jquery