Oct
12
Written by:
Michael Washington
10/12/2014 11:18 AM
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
);
}
}
// Do not allow a task to be called {New Task]
if (entity.TaskName == "[New Task]")
{
results.AddEntityError(
"Task cannot be named [New Task]"
);
}
// Do not allow more than 1 incomplete 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";
// Create a app and inject jaydata
var app = angular.module('app', ['jaydata']);
})();
Add the controller code to the file:
(function () {
// Create a ToDoEditorController injecting $scope and $data (for JayData)
angular.module('app')
.controller('ToDoEditorController', ['$scope', '$data',
function ToDoEditorController($scope, $data) {
// Create an empty ToDoes collection
$scope.ToDoes = [];
// Set the selectedToDo to nothing for now
$scope.selectedToDo = null;
// Call the /ApplicationData.svc LightSwitch OData service
$data.initService('/ApplicationData.svc').then(function (ApplicationData) {
$scope.ApplicationData = ApplicationData;
$scope.ToDoes = ApplicationData.ToDoes.toLiveArray();
});
// This will be called when the collection changes
Object.defineProperty($scope, "colToDoes", {
get: function () {
return $scope.ApplicationData
.ToDoes
.toLiveArray();
}
});
$scope.save = function () {
if ($scope.selectedToDo.Id) {
// Save an existing ToDo item
$scope.ApplicationData.ToDoes.attach($scope.selectedToDo, true);
$scope.selectedToDo.entityState = $data.EntityState.Modified;
}
else {
// Save a new ToDo item
$scope.ApplicationData.ToDoes.add($scope.selectedToDo, true);
}
$scope.saveChanges();
};
// Save any changes
$scope.saveChanges = function () {
$scope.ApplicationData.saveChanges()
.then(function () {
$scope.selectedToDo = null;
}, function (error) {
// Get the validation error messages from LightSwitch
var xml = error.message,
xmlDoc = $.parseXML(xml),
$xml = $(xmlDoc),
$ValidationResults = $xml.find("ValidationResults");
if ($ValidationResults[0].childNodes.length == 0) {
// This is a simple error
$MessageError = $xml.find("Message")[0].childNodes['0'].data;
alert($MessageError);
} else {
// This is a entity validation error
angular.forEach($ValidationResults, function (ValidationResult) {
angular.forEach(ValidationResult.childNodes, function (childNode) {
alert(childNode.childNodes[0].textContent);
});
});
}
$scope.ApplicationData.stateManager.reset();
});
};
$scope.remove = function () {
// Remove the ToDo item
$scope.ApplicationData.ToDoes.remove($scope.selectedToDo);
$scope.saveChanges();
};
$scope.newToDo = function () {
var ctx = $scope.ApplicationData;
// Add a new ToDo item
$scope.selectedToDo = new ctx.ToDoes.elementType({
// Set the default value for the Task Name
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="JayDataCRUD.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
type="text/javascript"></script>
<title>JayDataCRUD</title>
</head>
<body ng-cloak class="ng-cloak" data-ng-app="app">
<!-- Chrome control placeholder -->
<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">
// Set the style of the client web part page
// to be consistent with the host web.
(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;
//load the SharePoint resources
$(document).ready(function () {
//Get the URI decoded URL.
hostweburl =
decodeURIComponent(
getQueryStringParameter("SPHostUrl")
);
// The SharePoint js files URL are in the form:
// web_url/_layouts/15/resource
var scriptbase = hostweburl + "/_layouts/15/";
// Load the js file and continue to the
// success handler
$.getScript(scriptbase + "SP.UI.Controls.js", renderChrome)
});
//Function to prepare the options and render the control
function renderChrome() {
// The Help, Account and Contact pages receive the
// same query string parameters as the main page
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 to retrieve a query string value.
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:
Deploy A LightSwitch Application To Office 365 / SharePoint Online
Adding Additional Functionality
See the following articles for additional functionality added to this application:
AngularJS Posting To SharePoint Newsfeed Using Visual Studio LightSwitch
Creating SharePoint Word Documents with AngularJS using LightSwitch
Links – Microsoft
How to: Use the client chrome control in apps for SharePoint
SharePoint 2013: Use the chrome control in a cloud-hosted app
Links – JayData
Jaydata and AngularJS
Jaydata and AngularJS continued
Links – LightSwitch Help Website
Creating SharePoint Word Documents with AngularJS using LightSwitch
AngularJS Posting To SharePoint Newsfeed Using Visual Studio LightSwitch
Deploy A LightSwitch Application To Office 365 / SharePoint Online
Creating A SharePoint Online Testing Site
Exploring SharePoint 2013 Visual Studio Cloud Business Apps (LightSwitch)
Creating A LightSwitch SharePoint 2013 Multi-Tenant Provider-Hosted Application
Implementing Documents in a SharePoint 2013 Cloud Business App (LightSwitch)
Download Code
The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
(you must have Visual Studio 2013 (or higher) and a SharePoint developer site to run the code)
3 comment(s) so far...
nice
By benison on
3/4/2015 5:58 AM
|
I recently created an OData V4 data service using the non-LightSwitch non-WCF Web API 2 approach and managed to consume the data using ODatajs for V4 and Datajs for the older LightSwitch V3 svc. Interesting to write the client using Notepad (well that and VSCode). Pain, pain and then more pain heaped upon pain. LightSwitch protected me from so many pain points. Still it has given me a greater appreciation of how OData delivers it's SQL data down the pipes. I just wish you'd written this great article a month or so back ;). Fantastic work again thx Michael.
By Lloyd on
3/28/2016 4:59 AM
|
your blog is really nice and informative and it is really exclusive ,i got more information from your article please update this kind of information.
By shalini on
5/14/2016 5:07 AM
|