Environment Setup for Angular2 Development
Note: For this, Windows 2012 R2 OS machine for development is used. In which SharePoint 2013 server is also installed.
- Install node JS installer.
- Install Python 2.7.
- Install Visual Studio 2015 with Update 3.
- In may be a case where you may get the error during installation of Visual Studio. To resolve the error, you need to install required KB updates for Windows server 2012.
- Select Custom option and select only the below mentioned Features:
- Visual C++ (all options)
- Python tools for Visual Studio
- Microsoft Web Developer Tools
- Open Visual Studio 2015 From menu, click “Tools” click on “Options” under “Projects and Solutions”, select “External Web Tools”.
- Now arrange the locations of external tools. Create new path, if path is not existed click “OK” to save changes. Refer below image for this step.
- Install TypeScript_Dev14Fulll.exe to compile typescripts in Visual Studio.
- Check whether SharePoint add-in templates are available in the Visual Studio or not. (From Create new project section, you can check if these templates are available or not.) If templates are not available in the Visual Studio, then download Microsoft Office Developer Tools Preview 2 installer. Install it for further steps and don’t forget to select SharePoint add-in templates option .
- Open command prompt and Run command to set path for Python 2.7: npm config set python python2.7
- Also, run another command: npm config set msvs_version 2015 –global
Configuration for SharePoint Provider Hosted App
Follow Microsoft link to configure machine for SharePoint provider hosted app in on premise.
CRUD Operations in List Using SharePoint Provider Hosted App with Angular2
We are performing CRUD operations in the SharePoint Development where SharePoint list is residing in the host web. List name I have used static “TestAngular” with 2 fields Title, Number with single line column type.
- Create basic SharePoint Provider hosted app with MVC web application. Please follow Microsoft link.
- Open the appmanifest file of the SharePoint app from Solution explorer.
- Give “Manage” permissions on the site collection and list in appmanifest file.
- Create Web API controllers in MVC Web Application
Use static list name “TestAngular”. Change the code in class file with name “WebApiConfig.cs” in the “App_Start” folder. This enables the session for the Web API. Replace existing code with below code in “WebApiConfig.cs” file.
using System.Web;
using System.Web.Http;
using System.Web.Http.WebHost;
using System.Web.Routing;
using System.Web.SessionState;
namespace PHA_MVCWeb.App_Start
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandler();
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
public class SessionRouteHandler : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandler(requestContext.RouteData);
}
}
public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
{
public SessionControllerHandler(RouteData routeData)
: base(routeData)
{ }
}
}
} |
using System.Web;
using System.Web.Http;
using System.Web.Http.WebHost;
using System.Web.Routing;
using System.Web.SessionState;
namespace PHA_MVCWeb.App_Start
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandler();
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
public class SessionRouteHandler : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandler(requestContext.RouteData);
}
}
public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
{
public SessionControllerHandler(RouteData routeData)
: base(routeData)
{ }
}
}
}
- Create new class file inside Filters folder with name “SharePointContextWebAPIFilterAttribute.cs”.
- Add below code inside “SharePointContextWebAPIFilterAttribute.cs” file.
using System;
using System.Net;
using System.Net.Http;
using System.Web;
using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;
namespace PHA_MVCWeb.Filters
{
public class SharePointContextWebAPIFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
Uri redirectUrl;
switch (SharePointContextProvider.CheckRedirectionStatus(HttpContext.Current, out redirectUrl))
{
case RedirectionStatus.Ok:
return;
case RedirectionStatus.ShouldRedirect:
var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
response.Headers.Add("Location", redirectUrl.AbsoluteUri);
actionContext.Response = response;
break;
case RedirectionStatus.CanNotRedirect:
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Context couldn't be created: access denied");
break;
}
}
}
} |
using System;
using System.Net;
using System.Net.Http;
using System.Web;
using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;
namespace PHA_MVCWeb.Filters
{
public class SharePointContextWebAPIFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
Uri redirectUrl;
switch (SharePointContextProvider.CheckRedirectionStatus(HttpContext.Current, out redirectUrl))
{
case RedirectionStatus.Ok:
return;
case RedirectionStatus.ShouldRedirect:
var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
response.Headers.Add("Location", redirectUrl.AbsoluteUri);
actionContext.Response = response;
break;
case RedirectionStatus.CanNotRedirect:
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Context couldn't be created: access denied");
break;
}
}
}
}
- Notes (for above code):
- System.Web.Http.Controllers.HttpActionContext doesn’t have HttpContext object associated, so use HttpContext.Current instead of OnActionExecuting when called CheckRedirectionStatus method from SharePointContextProvider class.
- System.Web.Http.Controllers.HttpActionContext doesn’t have Result property, so use Response property to redirect and create Error response in the code.
- To create View Controller, create new Web API controller with name ViewController.cs inside the Controllers folder. This will retrieve all the items from the SharePoint list.
- Add below mentioned code in “ViewController.cs” file.
using System.Collections.Generic;
using System.Web.Http;
using Microsoft.SharePoint.Client;
using System.Web;
using PHA_MVCWeb.Filters;
namespace PHA_MVCWeb.Controllers
{
public class TestAngularModel
{
public string ID { get; set; }
public string Title { get; set; }
public string Number { get; set; }
public TestAngularModel(string ID, string Title, string Number)
{
this.ID = ID;
this.Title = Title;
this.Number = Number;
}
}
public class ViewController : ApiController
{
// GET api//5
[SharePointContextWebAPIFilter]
public List Get(int id)
{
List TestAngular = null;
ListItemCollection itmCol = null;
List itmList = new List();
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
clientContext.Load(TestAngular);
clientContext.ExecuteQuery();
itmCol = TestAngular.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(itmCol);
clientContext.ExecuteQuery();
foreach (ListItem itm in itmCol)
{
itmList.Add(new TestAngularModel(itm["ID"].ToString(), itm["Title"].ToString(), itm["Number"].ToString()));
}
return itmList;
}
else
return itmList;
}
}
} |
using System.Collections.Generic;
using System.Web.Http;
using Microsoft.SharePoint.Client;
using System.Web;
using PHA_MVCWeb.Filters;
namespace PHA_MVCWeb.Controllers
{
public class TestAngularModel
{
public string ID { get; set; }
public string Title { get; set; }
public string Number { get; set; }
public TestAngularModel(string ID, string Title, string Number)
{
this.ID = ID;
this.Title = Title;
this.Number = Number;
}
}
public class ViewController : ApiController
{
// GET api//5
[SharePointContextWebAPIFilter]
public List Get(int id)
{
List TestAngular = null;
ListItemCollection itmCol = null;
List itmList = new List();
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
clientContext.Load(TestAngular);
clientContext.ExecuteQuery();
itmCol = TestAngular.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(itmCol);
clientContext.ExecuteQuery();
foreach (ListItem itm in itmCol)
{
itmList.Add(new TestAngularModel(itm["ID"].ToString(), itm["Title"].ToString(), itm["Number"].ToString()));
}
return itmList;
}
else
return itmList;
}
}
}
- To create Item Controller, create new Web API controller with name “CreateItemController.cs” in “Controllers” folder. It will create new item in the SharePoint list.
- Add below code to “CreateItemController.cs” file.
using Microsoft.SharePoint.Client;
using PHA_MVCWeb.Filters;
using System.Web;
using System.Web.Http;
namespace PHA_MVCWeb.Controllers
{
public class CreateItemController : ApiController
{
[SharePointContextWebAPIFilter]
public string Get(string name, string number)
{
List TestAngular = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
clientContext.Load(TestAngular);
clientContext.ExecuteQuery();
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem oListItem = TestAngular.AddItem(itemCreateInfo);
oListItem["Title"] = name;
oListItem["Number"] = number;
oListItem.Update();
clientContext.ExecuteQuery();
return "Data saved!";
}
else
{
return "Error occurred!";
}
}
}
}
} |
using Microsoft.SharePoint.Client;
using PHA_MVCWeb.Filters;
using System.Web;
using System.Web.Http;
namespace PHA_MVCWeb.Controllers
{
public class CreateItemController : ApiController
{
[SharePointContextWebAPIFilter]
public string Get(string name, string number)
{
List TestAngular = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
clientContext.Load(TestAngular);
clientContext.ExecuteQuery();
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem oListItem = TestAngular.AddItem(itemCreateInfo);
oListItem["Title"] = name;
oListItem["Number"] = number;
oListItem.Update();
clientContext.ExecuteQuery();
return "Data saved!";
}
else
{
return "Error occurred!";
}
}
}
}
}
Similarly create controllers for update and delete item.
- Create “NPM configuration file” with name “package.json” at root level.
- Add below code in the package.json file. It contains information about dependencies of angular package with versions for compiler. Here Angular 2 with RC6 is used.
{
"name": "aspnet",
"version": "0.0.0",
"scripts": {
"postinstall": "typings install",
"typings": "typings"
},
"license": "ISC",
"devDependencies": {
"concurrently": "^2.2.0",
"lite-server": "^2.2.2",
"systemjs-builder": "^0.15.16",
"traceur": "^0.0.91",
"typescript": "2.0.2",
"typings":"^1.3.2"
},
"dependencies": {
"@angular/common": "2.0.0-rc.6",
"@angular/compiler": "2.0.0-rc.6",
"@angular/core": "2.0.0-rc.6",
"@angular/http": "2.0.0-rc.6",
"@angular/platform-browser": "2.0.0-rc.6",
"@angular/platform-browser-dynamic": "2.0.0-rc.6",
"@angular/upgrade": "2.0.0-rc.6",
"@angular/forms": "2.0.0-rc.6",
"@angular/router": "3.0.0-rc.2",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"systemjs": "^0.19.37",
"typings": "^1.3.2",
"zone.js": "^0.6.12",
"moment": "^2.14.1"
},
"main": "systemjs.config.js",
"author": "",
"description": ""
} |
{
"name": "aspnet",
"version": "0.0.0",
"scripts": {
"postinstall": "typings install",
"typings": "typings"
},
"license": "ISC",
"devDependencies": {
"concurrently": "^2.2.0",
"lite-server": "^2.2.2",
"systemjs-builder": "^0.15.16",
"traceur": "^0.0.91",
"typescript": "2.0.2",
"typings":"^1.3.2"
},
"dependencies": {
"@angular/common": "2.0.0-rc.6",
"@angular/compiler": "2.0.0-rc.6",
"@angular/core": "2.0.0-rc.6",
"@angular/http": "2.0.0-rc.6",
"@angular/platform-browser": "2.0.0-rc.6",
"@angular/platform-browser-dynamic": "2.0.0-rc.6",
"@angular/upgrade": "2.0.0-rc.6",
"@angular/forms": "2.0.0-rc.6",
"@angular/router": "3.0.0-rc.2",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"systemjs": "^0.19.37",
"typings": "^1.3.2",
"zone.js": "^0.6.12",
"moment": "^2.14.1"
},
"main": "systemjs.config.js",
"author": "",
"description": ""
}
- Create “TypeScript JSON Configuration file” with name “tsconfig.json” at root level.
- Add below code in the “tsconfig.json” file.
{
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules",
"node_modules/@types/jquery/index.d.ts",
"typings/main",
"typings/main.d.ts",
"wwwroot",
"Scripts/TypeLite.Net4.d.ts"
]
} |
{
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules",
"node_modules/@types/jquery/index.d.ts",
"typings/main",
"typings/main.d.ts",
"wwwroot",
"Scripts/TypeLite.Net4.d.ts"
]
}
- Create “JSON file” with name “typings.json” at root level.
- Add below code in “typings.json” file.
{
"ambientDependencies": {
"bootstrap": "github:DefinitelyTyped/DefinitelyTyped/bootstrap/bootstrap.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
"core-js": "registry:dt/core-js#0.0.0+20160317120654",
"jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
"TypeLite": "file:scripts/TypeLite.Net4.d.ts"
}
} |
{
"ambientDependencies": {
"bootstrap": "github:DefinitelyTyped/DefinitelyTyped/bootstrap/bootstrap.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
"core-js": "registry:dt/core-js#0.0.0+20160317120654",
"jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
"TypeLite": "file:scripts/TypeLite.Net4.d.ts"
}
}
- Create “JavaScript” file with name “systemjs.config.js” at root level. This file loads all packages required for the application while initialization.
- Add below code in “systemjs.config.js” file.
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': '/node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// angular testing umd bundles
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
'angular2-in-memory-web-api': {
defaultExtension: 'js'
}
}
});
})(this); |
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': '/node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// angular testing umd bundles
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
'angular2-in-memory-web-api': {
defaultExtension: 'js'
}
}
});
})(this);
- Create new “text” file with name “TypeLite.Net4.tt” in “Scripts” folder.
- Add below code in “TypeLite.Net4.tt” file.
<#@ template debug="false" hostspecific="True" language="C#" #>
<#@ assembly name="$(TargetDir)TypeLite.dll" #>
<#@ assembly name="$(TargetDir)TypeLite.Net4.dll" #>
<#@ assembly name="$(TargetDir)$(TargetFileName)" #>
<#@ import namespace="TypeLite" #>
<#@ import namespace="TypeLite.Net4" #>
<#@output extension=".d.ts"#>
<#@include file="Manager.ttinclude"#>
<# var manager = Manager.Create(Host, GenerationEnvironment); #>
<# var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.For()
.For<Models.ViewModel.JSONReturnVM<object width="300" height="150">>();#> <#= ts.Generate(TsGeneratorOutput.Properties) #> <# manager.StartNewFile("Enums.ts"); #><#= ts.Generate(TsGeneratorOutput.Enums) #><# manager.EndBlock(); #><# manager.Process(true); #>
<li>To create root – APP module for Angular2 application, create “app” folder at root level of web application.</li>
<li>Create new “typescript” file with name “main.ts” inside “app” folder. This file will load first and load the AppModule.</li>
<li>Add below code in “main.ts” file.
<pre lang="csharp">import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';import { AppModule } from './app.module';platformBrowserDynamic().bootstrapModule(AppModule); |
<#@ template debug="false" hostspecific="True" language="C#" #>
<#@ assembly name="$(TargetDir)TypeLite.dll" #>
<#@ assembly name="$(TargetDir)TypeLite.Net4.dll" #>
<#@ assembly name="$(TargetDir)$(TargetFileName)" #>
<#@ import namespace="TypeLite" #>
<#@ import namespace="TypeLite.Net4" #>
<#@output extension=".d.ts"#>
<#@include file="Manager.ttinclude"#>
<# var manager = Manager.Create(Host, GenerationEnvironment); #>
<# var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.For()
.For<Models.ViewModel.JSONReturnVM<object width="300" height="150">>();#> <#= ts.Generate(TsGeneratorOutput.Properties) #> <# manager.StartNewFile("Enums.ts"); #><#= ts.Generate(TsGeneratorOutput.Enums) #><# manager.EndBlock(); #><# manager.Process(true); #>
<li>To create root – APP module for Angular2 application, create “app” folder at root level of web application.</li>
<li>Create new “typescript” file with name “main.ts” inside “app” folder. This file will load first and load the AppModule.</li>
<li>Add below code in “main.ts” file.
<pre lang="csharp">import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';import { AppModule } from './app.module';platformBrowserDynamic().bootstrapModule(AppModule);
Comments