SharePoint 2013: Create SharePoint Hosted App in Visual Studio

Recently I got rolled off from a SharePoint 2010 project for few weeks. So, I decided to spend some of my free time on SharePoint 2013. Since apps are a new concept in SP 2013 I decided to create some sample apps. I did not make any production apps as I am yet to get allocated on a project which uses SP 2013 apps. In this series of blog posts I will try to share my leanings. 
This series will consist of following posts:
Develop SharePoint 2013 apps with NAPA
Access data in Host web
Isolated App domain Setup Issues
Create SharePoint Hosted App in Visual Studio
Provider Hosted App Development Prerequisites
App Event Receivers
Remote Event Receivers
In this post we will see how to create a SharePoint Hosted app. The app will display different RSS feeds. SharePoint-Hosted apps only allow coding using Javascript client object model and REST API. No server side code is allowed. The assumption is that your development environment is properly set up for developing apps. 

Open Visual Studio and create a new project and select App for SharePoint 2013 template and name the app as RSSViewerApp.

App For SharePoint

Provide the name of the site where you want to debug the app. In my case I have provided the url of the developer site on my VM. You can also provide the url of the O365 site. A site based on Developer site template allows us to directly deploy the apps to the site. Finally, select SharePoint-Hosted from the drop down and click on Finish.

SharePoint Hosted

In this app we will store the feed information in a SharePoint list. So, we will create few site columns, a content type and then use this content type in a custom SharePoint list.
Right click on the project -> Add -> New Item. Select Site Column template and name the file SiteColumns.

Site Column

Replace the contents of the Elements.xml file with following XML code and save the file.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Field
       ID="{16225AD4-4F94-4B11-9DEF-7941BF410EB1}"
       Name="FeedUrl"
       DisplayName="Feed Url"
       Type="Text"
       Required="TRUE"
       Group="RSSViewer Site Columns">
  </Field>
  <Field
       ID="{AA002B89-7543-4A44-BAD9-E8B6EB5A3921}"
       Name="NumberOfFeedItems"
       DisplayName="Number of feed items"
       Type="Number"
       Required="TRUE"
       Group="RSSViewer Site Columns">
  </Field>
  <Field
       ID="{A4D69434-ED4A-4CD6-B3C2-FD8474FB0843}"
       Name="ShowPublishDate"
       DisplayName="Show publish date"
       Type="Boolean"
       Required="FALSE"
       Group="RSSViewer Site Columns">
    <Default>1</Default>
  </Field>
  <Field
       ID="{0C28C525-1634-437E-9B45-326164AC9DB9}"
       Name="OpenLinksInNewWindow"
       DisplayName="Open links in new window"
       Type="Boolean"
       Required="FALSE"
       Group="RSSViewer Site Columns">
    <Default>1</Default>
  </Field>
</Elements>
Here we create four site columns:
  • Feed Url: A text column storing the url of the feed.
  • Number of feed items: A number column to store the number of items to be shown from a particular feed.
  • Show publish date: A boolean to show or not show published date.
  • Open links in new window: A boolean which indicates whether to show link in same or new window.
Now select project and Content Type to it and name it RSSViewerContentType as shown:

Content Type

In choose content type settings select item from the drop down and click on Finish.

Item


Now add the columns created in earlier step to the content type using the grid and save the file:

Configure Columns

Now add the list to the project. The list will use the content type created in the earlier step.

List Instance

Give the name to the list and select "Deafult(Custom List)" template and click Finish.

Custom List

Click on Content Types at the bottom and RSS Viewer Content type created earlier.

Add Content Type

Delete Folder and Item content type and keep RSS Viewer content type only and save the file.

List Columns

We are done with setting up of the configuration list for RSS Viewer app. Go to Pages folder and open Default.aspx file and replace below code:
<div>
    <p id="message">
        <!-- The following content will be replaced with the user name when you run the app - see App.js -->
        initializing...
    </p>
</div>
with following code:
<script type="text/javascript">
    SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () { sharePointReady(); });
          </script>
<div id="link">        

</div>
<div id="feed">

</div>
The code for sharePointReady() will be defined in the App.js file present in Scripts folder. Open App.js file and replace its code with following code:
'use strict';
var ctx;
var web;
var collListItem;
var title;
var feedUrl;
var numberOfFeedItems;
var showPublishDate;
var openLinksInNewWindow;
google.load("feeds", "1");

function sharePointReady() {
    this.ctx = new SP.ClientContext.get_current();        
    getFeeds();
}

function  getFeeds() {
    this.web = ctx.get_web();
    this.ctx.load(this.web);
    this.ctx.executeQueryAsync(Function.createDelegate(this, this.onWebSuccess), Function.createDelegate(this, this.onWebFail));
    var list = this.web.get_lists().getByTitle('RSS Feed Viewer Config List');
    var camlQuery = new SP.CamlQuery();    
    this.collListItem = list.getItems(camlQuery);
    this.ctx.load(collListItem, 'Include(Title, FeedUrl, NumberOfFeedItems, ShowPublishDate, OpenLinksInNewWindow)');
    this.ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFail));
}

function onWebSuccess(sender, args) {    
    var linkContainer = document.getElementById("link");
    linkContainer.innerHTML = '<p><a href=' + this.web.get_url() + '/Lists/RSSFeedViewerConfigList  > Configure Feed </a></p>';   
}

function onWebFail(sender, args) {
    alert('failed to get web info . Error:' + args.get_message());
}

function onSuccess(sender, args) {
    var listItemEnumerator = collListItem.getEnumerator();
    while (listItemEnumerator.moveNext()) {
        var oListItem = listItemEnumerator.get_current();
        this.title = oListItem.get_item('Title');
        this.feedUrl = oListItem.get_item('FeedUrl');
        this.numberOfFeedItems = oListItem.get_item('NumberOfFeedItems');
        this.showPublishDate = oListItem.get_item('ShowPublishDate');
        this.openLinksInNewWindow = oListItem.get_item('OpenLinksInNewWindow');                
        initialize();
    }
}

function onFail(sender, args) {
    alert('failed to get list item info . Error:' + args.get_message());
}

function initialize() {    
    var feed = new google.feeds.Feed(this.feedUrl);
    feed.setNumEntries(this.numberOfFeedItems);    
    var isOpnenInNew = this.openLinksInNewWindow;
    var showPubDate = this.showPublishDate;
    var feedTitle = this.title;
    feed.load(function (result) {
        if (!result.error) {            
            var container = document.getElementById("feed");
            var html = '';
            html += '<h2>' + feedTitle + '</h2>';
            for (var i = 0; i < result.feed.entries.length; i++) {
                var entry = result.feed.entries[i];                
                if (isOpnenInNew) {                   
                    html += '<p><a href=' + entry.link + ' target=_blank > ' + entry.title + ' </a></p>';
                }
                else {                   
                    html += '<p><a href=' + entry.link + '> ' + entry.title + ' </a></p>';
                }
                if (showPubDate) {
                    html += '<p>' + entry.publishedDate + '</p>';
                }
                html += '<p>' + entry.content + '</p>';                
            }           
            container.insertAdjacentHTML('beforeend', html);
        }
    });    
}
Code explanation:
  • The code creates a link to the Configuration list.
  • It iterates through the items in the configuration list, reads the feed information and finally loads the feed using Google JSAPI.
Lastly, download the JSAPI file from Google and add it to the Scripts folder and add its reference in the Default.aspx page.

JS API

However, you can also skip downloading it and refer it in the Default.aspx file if you have internet connectivity on your VM.
The final code in the Default.aspx page looks like this:
<%-- The markup and script in the following Content element will be placed in the <head> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <script type="text/javascript" src="../Scripts/jquery-1.7.1.min.js"></script>
    <script type="text/javascript" src="../Scripts/jsapi.js"></script>
    <!--<script type="text/javascript" src="https://www.google.com/jsapi"></script>-->
    <script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
    <script type="text/javascript" src="/_layouts/15/sp.js"></script>

    <!-- Add your CSS styles to the following file -->
    <link rel="Stylesheet" type="text/css" href="../Content/App.css" />

    <!-- Add your JavaScript to the following file -->
    <script type="text/javascript" src="../Scripts/App.js"></script>
</asp:Content>

<%-- The markup in the following Content element will be placed in the TitleArea of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
    RSS Viewer
</asp:Content>

<%-- The markup and script in the following Content element will be placed in the <body> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <script type="text/javascript">
        SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () { sharePointReady(); });
              </script>
    <div id="link">        

    </div>
    <div id="feed">

    </div>

</asp:Content>

Now click on Start to launch the application. You may be asked to provide the username and password to login to the site.
The application will look like below:

Initial RSS View APP

Click on Configure Feed link. The Configuration list will appear:

Configuration List

Click on new item to enter feed information.

CNN Top Stories

Here I added three items in the list.

Feeds

Now click on the RSSFeedViewerApp on the top so that you are taken to the landing page of the app. Observer the feed getting displayed on the page.

Feed Display

profile for Nadeem Yousuf at SharePoint Stack Exchange, Q&A for SharePoint enthusiasts

+