You can create SharePoint Provider Hosted applications using AngularJS and Visual Studio LightSwitch. This will allow you to create applications faster and easier.
The application we will create in this article will display a list of Tasks, as well as the user who created the Task. To edit an existing Task, we click on the Task. To create a new Task, we click the add new button.
To save a new Task or edit an existing Task, we enter the data and click the Save button. If we wanted to delete an existing Task, we would click the Remove button.
The application also demonstrates how to implement business rules and security.
Why Would You Want to Use AngularJS with LightSwitch?
- You need 100% control over the UI – The one disadvantage the LightSwitch HTML Client has is its dependence on JQuery Mobile. This is fine in most cases but you would have a hard time matching a pixel by pixel design specification using it.
- You need to implement security – Security must be implemented on the server-side. You cannot implement security inside AngularJS because it is a client-side technology. LightSwitch makes security easy as we will demonstrate in this example.
- You want to use LightSwitch for the Administration screens – AngularJS screens take a lot longer to create than a standard LightSwitch screen. However, there is no need to code all the screens in your application in AngularJS. As this example will demonstrate, you can mix AngularJS and LightSwitch screens in the same application.
- You want to build a OData service layer for use with other applications – LightSwitch is the easiest and most robust way to create an OData service.
- You want to speed up development – There is a lot less code to implement when you use LightSwitch as your back-end. This means faster development and fewer bugs.
Using Web API vs. Calling OData Directly
You can use LightSwitch as a back-end for AngularJS using Web API as demonstrated in the article, Creating an AngularJS CRUD Application Using Visual Studio LightSwitch. The structure looks like this:
However, you can consume your backend OData Visual Studio LightSwitch services in directly in AngularJS using JayData (as demonstrated in the article: Using JayData to Consume the Visual Studio LightSwitch OData Business Layer in a AngularJS CRUD Application). This will save you a lot of development time and reduce the code you will be required to write. The structure looks like this:
In the example in this article, we will call the LightSwitch OData service layer directly.
Create the Project
In Visual Studio 2013, we create a New Project.
We create a Cloud Business App.
We will be prompted to enter a SharePoint development site.
Click Finish.
The project will be created.
The Solution will display.
Add Data Source and Business Logic
In the Server
project, right-click on the Data Sources folder and select Add Table.
Create the ToDo
table.
In the Write Code menu, select the Validate
method.
Use the following code for the method:
partial void ToDoes_Validate(ToDo entity, EntitySetValidationResultsBuilder results)
{
if (entity.Details.EntityState == EntityState.Modified)
{
if (entity.CreatedByInfo.Id != this.Application.User.Id)
{
results.AddEntityError(
"Task can only be modified by " + entity.CreatedByInfo.Identity.Name
);
}
}
if (entity.TaskName == "[New Task]")
{
results.AddEntityError(
"Task cannot be named [New Task]"
);
}
if (entity.IsComplete == false)
{
int intCountOfIncomplete =
this.DataWorkspace.ApplicationData.ToDoes
.Where(x => x.IsComplete == false).Count();
if (intCountOfIncomplete > 0)
{
results.AddEntityError(
"Cannot have more than 1 incomplete Task"
);
}
}
Return to the table designer, and in the Write Code menu, select the Deleting
method.
Use the following code for the method:
partial void ToDoes_Deleting(ToDo entity)
{
if (entity.CreatedByInfo.Id != this.Application.User.Id)
{
throw new ValidationException("Task can only be deleted by "
+ entity.CreatedByInfo.Identity.Name);
}
}
Create the LightSwitch HTML Client Screens
In the HTMLClient
project, right-click on the Screens folder and select Add Screen.
Use the Common Screen Set template to create screens for the ToDo
entity.
The screens will be created.
Run the project.
You will be required to log into your SharePoint developer site.
The application will be side-loaded into your SharePoint development site.
Your web browser will open and you be required to log into your SharePoint developer site.
You will be required to Trust the application.
The application will load and you will have the ability to add and edit To Do items.
You will note that the validation and business rules are enforced.
Close the web browser and return to Visual Studio.
Create the AngularJS Application
Right-click on the Server
project and select Manage NuGet Packages.
Install AngularJS.
Install JayData.
Create a folder in the Server
project called Pages.
Right-click on the Pages folder and add a new JavaScript file.
Name the file JayDataCRUD.
Add the following code to the file to create the Angular App:
(function () {
"use strict";
var app = angular.module('app', ['jaydata']);
})();
Add the controller code to the file:
(function () {
angular.module('app')
.controller('ToDoEditorController', ['$scope', '$data',
function ToDoEditorController($scope, $data) {
$scope.ToDoes = [];
$scope.selectedToDo = null;
$data.initService('/ApplicationData.svc').then(function (ApplicationData) {
$scope.ApplicationData = ApplicationData;
$scope.ToDoes = ApplicationData.ToDoes.toLiveArray();
});
Object.defineProperty($scope, "colToDoes", {
get: function () {
return $scope.ApplicationData
.ToDoes
.toLiveArray();
}
});
$scope.save = function () {
if ($scope.selectedToDo.Id) {
$scope.ApplicationData.ToDoes.attach($scope.selectedToDo, true);
$scope.selectedToDo.entityState = $data.EntityState.Modified;
}
else {
$scope.ApplicationData.ToDoes.add($scope.selectedToDo, true);
}
$scope.saveChanges();
};
$scope.saveChanges = function () {
$scope.ApplicationData.saveChanges()
.then(function () {
$scope.selectedToDo = null;
}, function (error) {
var xml = error.message,
xmlDoc = $.parseXML(xml),
$xml = $(xmlDoc),
$ValidationResults = $xml.find("ValidationResults");
if ($ValidationResults[0].childNodes.length == 0) {
$MessageError = $xml.find("Message")[0].childNodes['0'].data;
alert($MessageError);
} else {
angular.forEach($ValidationResults, function (ValidationResult) {
angular.forEach
(ValidationResult.childNodes, function (childNode) {
alert(childNode.childNodes[0].textContent);
});
});
}
$scope.ApplicationData.stateManager.reset();
});
};
$scope.remove = function () {
$scope.ApplicationData.ToDoes.remove($scope.selectedToDo);
$scope.saveChanges();
};
$scope.newToDo = function () {
var ctx = $scope.ApplicationData;
$scope.selectedToDo = new ctx.ToDoes.elementType({
TaskName: "[New Task]"
});
};
}]);
})();
Right-click on the Pages folder and add a new Web Form file.
(You could use a normal .html page but you may have to configure your local IIS Express to run the page in this context so we are just avoiding the issue by using a Web Form page. You can also use a MVC page, but again we are avoiding the extra steps to enable MVC in the project.)
Name the file JayDataCRUD.
The file will be created.
Change the code in the markup to the following:
<%@ Page Language="C#"
AutoEventWireup="true"
CodeBehind="JayDataCRUD.aspx.cs"
Inherits="LightSwitchApplication.Pages.JayDataCRUD" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE-8" />
<script src="../Scripts/jquery-1.8.0.js"></script>
<script src="../Scripts/angular.js"></script>
<script src="../Scripts/datajs-1.0.3.js"></script>
<script src="../Scripts/jaydata.js"></script>
<script src="../Scripts/jaydatamodules/angular.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
type="text/javascript"></script>
<script src="JayDataCRUD.js"></script>
<title>JayDataCRUD</title>
</head>
<body ng-cloak class="ng-cloak" data-ng-app="app">
<div id="chrome_ctrl_placeholder"></div>
<div id="MainContent" data-ng-controller="ToDoEditorController">
<table>
<tr data-ng-repeat="ToDo in colToDoes">
<td>
<input id="checkbox" type="checkbox"
data-ng-model="ToDo.IsComplete" disabled="disabled"></td>
<td>
<a href="#"
data-ng-click="$parent.selectedToDo = ToDo">{{ToDo.TaskName}}</a>
</td>
<td>[{{ToDo.CreatedBy}}]</td>
</tr>
</table>
<p>
<button class="button normaltext" data-ng-click="newToDo()">add new</button></p>
<form data-ng-if="selectedToDo">
<fieldset style="width: 300px;">
<legend>{{selectedToDo.TaskName}}</legend>
<br />
<label>
<span><strong>Id:</strong></span>
<span>{{selectedToDo.Id}}</span>
<span>
<br />
<strong>Task Name:</strong>
</span>
<input data-ng-model="selectedToDo.TaskName" size="20" />
<span>
<br />
<strong>Is Complete:</strong>
</span>
<input type="checkbox" data-ng-model="selectedToDo.IsComplete" />
<br />
<br />
</label>
<button data-ng-click="save()">Save</button>
<button data-ng-click="remove()">Remove</button>
</fieldset>
</form>
</div>
</body>
</html>
Configure the AngularJS Page to Load
In the SharePoint project, double-click on the AppManifest.xml file to open it.
Select the JayDataCRUD.aspx page as the Start Page.
Run the AngularJS Application
When we run the application, we will have to Trust it again (because we modified the SharePoint configuration for the application).
The AngularJS application will load.
The security and business rules will be enforced.
Match the Style of the SharePoint Site
To style the application to match the SharePoint site, we add the following to the JayDataCRUD.aspx file:
<script type="text/javascript">
(function () {
'use strict';
var hostUrl = '';
if (document.URL.indexOf('?') != -1) {
var params = document.URL.split('?')[1].split('&');
for (var i = 0; i < params.length; i++) {
var p = decodeURIComponent(params[i]);
if (/^SPHostUrl=/i.test(p)) {
hostUrl = p.split('=')[1];
document.write('<link rel="stylesheet" href="'
+ hostUrl + '/_layouts/15/defaultcss.ashx" />');
break;
}
}
}
if (hostUrl == '') {
document.write('<link rel="stylesheet"'
+ 'href="/_layouts/15/1033/styles/themable/corev15.css" />');
}
})();
</script>
Now when we run the application, the styles match.
Add the SharePoint Chrome (Logo and Toolbar)
To create a SharePoint Chrome (the title bar, logo, help icon and a “gear” icon that contains links to other pages in the application), we add a JavaScript file called ChromeLoader.js to the Scripts directory (and add a reference to it in the JayDataCRUD.aspx file).
We use the following code for the file:
var hostweburl;
$(document).ready(function () {
hostweburl =
decodeURIComponent(
getQueryStringParameter("SPHostUrl")
);
var scriptbase = hostweburl + "/_layouts/15/";
$.getScript(scriptbase + "SP.UI.Controls.js", renderChrome)
});
function renderChrome() {
var options = {
"appIconUrl": hostweburl + "/_layouts/15/images/siteicon.png",
"appTitle": "AngularJS CRUD App",
"appHelpPageUrl": "JayDataCRUD.aspx?"
+ document.URL.split("?")[1],
"settingsLinks": [
{
"linkUrl": "../HTMLClient/default.htm?"
+ document.URL.split("?")[1],
"displayName": "LightSwitch Application"
}
]
};
var nav = new SP.UI.Controls.Navigation(
"chrome_ctrl_placeholder",
options
);
nav.setVisible(true);
}
function getQueryStringParameter(paramToRetrieve) {
var params =
document.URL.split("?")[1].split("&");
var strParams = "";
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve)
return singleParam[1];
}
}
The application is now complete.
Clicking the “gear” icon will display a link to take us to the LightSwitch pages we created earlier.
Publishing and Deploying
Even though we have added AngularJS added to the project, it is still a LightSwitch project. Therefore to deploy, follow the directions here:
Links – Microsoft
Links – JayData
Links – LightSwitch Help Website