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
<%@ 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
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
<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>
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
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()); } }
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
<%@ 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>
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.
Category: Blog, SharePoint 2010, SharePoint 2013
[…] you haven’t checked out Part 1, please have a look. I’ve made some changes since then. I’ll be going over the changes […]
[…] you haven’t checked out Part 1, please have a look. I’ve made some changes since then. I’ll be going over the changes […]
What is the use of ?
Could you please explain this?