Experimenting with AngularJS inside a SharePoint Visual Web Part

One day, I was having breakfast with a JavaScript guru buddy of mine and I asked him, what is the latest development trend on the web these days? One of the things he mentioned was AngularJS by Google. That got me thinking... can I use this in SharePoint some how? Well, outlined below is my little experiment with AngularJS inside a SharePoint Visual Web Part.

Start a new Visual Web Part project

 

I'll be deploying my project to SharePoint 2013, so here is a screenshot of the Visual Studio 2012 New Project wizard. I'll be deploying the project as a farm solution because I'll need to deploy some JavaScript files to the LAYOUTS directory.

Once the project is ready, there should a file called VisualWebPart1.ascx created. This is where all the magic happens. Lets add 'Hello World' to it, and deploy.

VisualWebPart1.ascx Hello World

[code lang="csharp"]
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1.ascx.cs" Inherits="MyFirstVisualWebPart.VisualWebPart1.VisualWebPart1" %>

Hello World
[/code]

Add Web Part to Page

Add the Visual Web Part to a Page. If you see Hello World, then we are ready to begin the real experiment.

Beginning of the AngularJS experiment

My Web Part is going to be a simple form with a few questions and a text box for entering the answers. Answers get saved to a SharePoint list via JavaScript Object Model (JSOM).

The HTML

[code lang="html"]

<h1>My First Visual WebPart featuring Angular.js</h1>

<div ng-app>
<div ng-controller="QuestionnaireCtrl">
<ol>
<li ng-repeat="question in questions">
<span>{{question.text}}</span>
<br />
<input type="text" ng-model="question.answer"/>
</li>
</ol>
<input type="submit" value="Submit" ng-click="addAnswers($event)"/>
</div>
</div>

[/code]

Here I am initializing the AngularJS App on a div with the ng-app tag. Then I have a ng-controller called QuestionnaireCtrl which contains a bunch of questions that I loop through using ng-repeat.

The JavaScript

[code lang="javascript"]
var siteUrl = "<%= SPContext.Current.Web.Url %>";

function QuestionnaireCtrl($scope) {

$scope.questions = [
{ text: 'How would you like your eggs done?', answer: "" },
{ text: 'What kind of bread would you like?', answer: "" },
{ text: 'What kind of drink would you like?', answer: "" }
];

$scope.addAnswers = function ($event) {
$event.preventDefault();

var clientContext = new SP.ClientContext(siteUrl);
var web = clientContext.get_web();
var list = web.get_lists().getByTitle('FoodQuestions');

_.each($scope.questions, function (question, i) {
// create the ListItemInformational object
var listItemInfo = new SP.ListItemCreationInformation();
// add the item to the list
var listItem = list.addItem(listItemInfo);
// Assign Values for fields
listItem.set_item('Question', question.text);
listItem.set_item('Answer', question.answer);
listItem.set_item('Title', 'Question ' + (++i));

listItem.update();
});

clientContext.executeQueryAsync(
Function.createDelegate(this, onQuerySucceeded),
Function.createDelegate(this, onQueryFailed)
);

};

onQuerySucceeded = function () {
alert('Thank you, have a nice day.');

var questions = $scope.questions;
_.each(questions, function (question) {
question.answer = "";
});
$scope.$apply();
}

onQueryFailed = function (sender, args) {
alert('Request failed. ' + args.get_message() + 'n' + args.get_stackTrace());
}
}
[/code]

In the JavaScript, I hard coded 3 questions. Then I have a click event handler that triggers $scope.addAnswers, which will save the answers to my questions into a SharePoint list.

VisualWebPart1.ascx final product

[code lang="html"]
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1.ascx.cs" Inherits="MyFirstVisualWebPart.VisualWebPart1.VisualWebPart1" %>
<script src="/_layouts/15/MyFirstVisualWebPart/underscore-min.js"></script>
<script src="/_layouts/15/MyFirstVisualWebPart/angular.min.js"></script>
<script>
var siteUrl = "<%= SPContext.Current.Web.Url %>";

function QuestionnaireCtrl($scope) {

$scope.questions = [
{ text: 'How would you like your eggs done?', answer: "" },
{ text: 'What kind of bread would you like?', answer: "" },
{ text: 'What kind of drink would you like?', answer: "" }
];

$scope.addAnswers = function ($event) {
$event.preventDefault();

var clientContext = new SP.ClientContext(siteUrl);
var web = clientContext.get_web();
var list = web.get_lists().getByTitle('FoodQuestions');

_.each($scope.questions, function (question, i) {
// create the ListItemInformational object
var listItemInfo = new SP.ListItemCreationInformation();
// add the item to the list
var listItem = list.addItem(listItemInfo);
// Assign Values for fields
listItem.set_item('Question', question.text);
listItem.set_item('Answer', question.answer);
listItem.set_item('Title', 'Question ' + (++i));

listItem.update();
});

clientContext.executeQueryAsync(
Function.createDelegate(this, onQuerySucceeded),
Function.createDelegate(this, onQueryFailed)
);

};

onQuerySucceeded = function () {
alert('Thank you, have a nice day.');

var questions = $scope.questions;
_.each(questions, function (question) {
question.answer = "";
});
$scope.$apply();
}

onQueryFailed = function (sender, args) {
alert('Request failed. ' + args.get_message() + 'n' + args.get_stackTrace());
}
}
</script>

<h1>My First Visual WebPart featuring Angular.js</h1>

<div ng-app>

<div ng-controller="QuestionnaireCtrl">

<ol>
<li ng-repeat="question in questions">
<span>{{question.text}}</span>
<br />
<input type="text" ng-model="question.answer"/>
</li>
</ol>

<input type="submit" value="Submit" ng-click="addAnswers($event)"/>

</div>

</div>

[/code]

Congrats if you were able to follow along. I know I left out quite a bit of detail, so please let me know. As this is an experiment, pointers would be great too. I can post my whole Visual Studio project on github or somewhere if anybody is interested.

Thanks for reading.

It’s Time To Transform

Let us show you how much easier your work life can be with Bonzai Intranet on your team.