SharePoint Hosted App with Angular

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.

  1. Install node JS installer.
  2. Install Python 2.7.
  3. Install Visual Studio 2015 with Update 3.
  4. 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.
  5. Select Custom option and select only the below mentioned Features:
    1. Visual C++ (all options)
    2. Python tools for Visual Studio
    3. Microsoft Web Developer Tools
  6. Open Visual Studio 2015  From menu, click “Tools”  click on “Options”  under “Projects and Solutions”, select “External Web Tools”.
  7. 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.Arrange the locations of external tools
  8. Install TypeScript_Dev14Fulll.exe to compile typescripts in Visual Studio.
  9. 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 .
  10. Open command prompt and Run command to set path for Python 2.7: npm config set python python2.7
  11. 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.

  1. Create basic SharePoint Provider hosted app with MVC web application. Please follow Microsoft link.
  2. Open the appmanifest file of the SharePoint app from Solution explorer.
  3. Give “Manage” permissions on the site collection and list in appmanifest file.Manage Permissions
  4. 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)
            { }
        }
    }
}
  1. Create new class file inside Filters folder with name “SharePointContextWebAPIFilterAttribute.cs”.
  2. 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;
            }
        }
    }
}
  • 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.
  1. 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.
  1. 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;
            }
        }
    }
  1. 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.
  2. 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!";
                }
            }
        }
    }
}

Similarly create controllers for update and delete item.

  1. Create “NPM configuration file” with name “package.json” at root level.
  1. 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": ""
}
  1. Create “TypeScript JSON Configuration file” with name “tsconfig.json” at root level.
  2. 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"
  ]
}
  1. Create “JSON file” with name “typings.json” at root level.
  2. 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"
  }
}
  1. Create “JavaScript” file with name “systemjs.config.js” at root level. This file loads all packages required for the application while initialization.
  2. 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);
  1. Create new “text” file with name “TypeLite.Net4.tt” in “Scripts” folder.
  2. 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);
  1. Create new typescript file with name “app.module.ts” inside “app” folder. Main.ts file will load this file first while initialization of application. The file defines modules that are used in application.
  2. Add below code in “app.module.ts” file.
import { NgModule } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { Route, RouterModule } from '@angular/router';import { HttpModule } from '@angular/http';import { FormsModule } from '@angular/forms';import { routing } from './app.routes';import { AppComponent } from './app.component';import { ViewComponent } from './viewComponent/view.component';@NgModule({    imports: [BrowserModule, HttpModule, RouterModule, FormsModule, routing],    declarations: [AppComponent, ViewComponent],    bootstrap: [AppComponent]})export class AppModule { }
  1. Create new “typescript” file with name “app.component.ts” in “app” folder. The file will load content for first page.
  2. Add below code in “app.component.ts” file.
import { Component,} from '@angular/core';import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';import { FormsModule } from '@angular/forms';import { ViewDataService } from './services/viewData.service';@Component({    moduleId: module.id,    selector: 'app-work',    providers: [ViewDataService],    templateUrl: 'app.component.html'})export class AppComponent {}
  1. Create new “html” file with name “app.component.html” in “app” folder. The file contains html part of first page.
  2. Add below code in “app.component.html” file.
<div class="row">
<div class="col-md-12">
<h2>CRUD Operations using Angular2!</h2>
<hr>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-sm-3">
<div class="sidebar-nav">
<div class="navbar-collapse collapse sidebar-navbar-collapse">
<ul class="nav navbar-nav">
 	<li><a routerlinkactive="active" routerlink="/viewcomponent" routerlinkactiveoptions="" exact:="" true="">View all items</a></li>
 	<li><a routerlinkactive="active" routerlink="/createitem">Create new item</a></li>
 	<li><a routerlinkactive="active" routerlink="/updatecomponent">Update item</a></li>
 	<li><a routerlinkactive="active" routerlink="/deletecomponent" href="#">Delete item</a></li>
</ul>
</div>
</div>
</div>
<div class="col-md-9">        <router-outlet></router-outlet></div>
</div>
  1. To create viewData.service.ts ,create new folder with name “services” in “app” folder.
  2. Create new “typescript” file with name “viewData.service.ts” in “services” folder. It will access Web API “viewController” which is created before.
  3. Add below code in “viewData.service.ts” file.Note: Here static url is used for demo purpose.
import { Injectable } from '@angular/core';import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';@Injectable()export class ViewDataService {    constructor(private _http: Http) {    }    viewData() {        let listUrl = `https://localhost/api/view/1?SPHostUrl=https%3A%2F%2Ftatvasoft607%2Esharepoint%2Ecom%2Fsites%2FProviderApp&SPLanguage=en-US&SPClientTag=0&SPProductNumber=16%2E0%2E6406%2E1200&SPAppWebUrl=https%3A%2F%2FTatvasoft607-69192fd3dcf4a6%2Esharepoint%2Ecom%2Fsites%2FProviderApp%2FPHA_MVC`;        let reqOptions = new RequestOptions({            url: listUrl,            method: RequestMethod.Get,            headers: new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' }),            body: null        });        let req = new Request(reqOptions)        return this._http.request(req).map((res) => {            return res.json()        });    }}
  1. To createData.service.ts, create new “typescript” file with name “createData.service.ts” in “services” folder. It will access Web API “CreateItemController” which is created before.
  2. Add below code “createData.service.ts” file.Note: Here the static url is used for demo purpose.
import { Injectable } from '@angular/core';import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';@Injectable()export class CreateItemService {    constructor(private _http: Http) {    }    updateItem(id: string, title: string, number: string) {        let listUrl = `https://localhost/api/createitem? name=${title}&number=${number}&SPHostUrl=https%3A%2F%2Ftatvasoft607%2Esharepoint%2Ecom%2Fsites%2FProviderApp&SPLanguage=en-US&SPClientTag=0&SPProductNumber=16%2E0%2E6406%2E1200&SPAppWebUrl=https%3A%2F%2FTatvasoft607-69192fd3dcf4a6%2Esharepoint%2Ecom%2Fsites%2FProviderApp%2FPHA_MVC`;        let reqOptions = new RequestOptions({            url: listUrl,            method: RequestMethod.Get,            headers: new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' }),            body: null        });        let req = new Request(reqOptions)        return this._http.request(req).map((res) => {            return res.json()        });    }}
  1. This way you can create services for update and delete operations.
  2. To create ViewComponent, create new folder with name “viewComponent” in “app” folder.
  3. Create new “typescript” file with name “view.component.ts” in “viewComponent” folder.
import { Component, OnInit, Input } from '@angular/core';import { ViewDataService } from '../services/viewData.service';@Component({    selector: 'view-item',    providers: [ViewDataService],    template: `
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody>
<tr ngfor="let frnd of results;">
<td>{{frnd.Title}} {{last}}</td>
<td>{{frnd.Number}}</td>
</tr>
</tbody>
</table>
 
`})export class ViewComponent implements OnInit {    results: Array<object>;            constructor(private _viewDataService: ViewDataService) {    }    ngOnInit() {               this._viewDataService.viewData().subscribe(data => this.results = data);            }}</object>
  • Open “index.cshtml” from “Views” folder. Here all required JavaScript libraries are attached as per hierarchy.
  • Replace existing code of “index.cshtml” file with below one.
@{
    ViewBag.Title = "Home Page";
}
<!-- 1. Include JS libraries -->
<!-- 2. Configure SystemJS -->
    System.import('app/main');
    System.import('app').catch(function (err) { console.error(err); });
  • Loading…
  • To create Item Component, create new folder with name “CreateItemComponent” in “app” folder.
  • Create new “typescript” file with name “createItem.component.ts” in “CreateItemComponent” folder.
  • Add below code in “createItemModule.ts” file.
export class createItemModule {
    constructor(public name: string, public number: string) { }
}
  • Create new “typescript” file with name “createItem.component.ts” in “CreateItemComponent” folder.
  • Add below code in “createItem.component.ts” file.
import { Component } from '@angular/core';
import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';
import { FormsModule } from '@angular/forms';
import { createItemModule } from './createItemModule';
import { Router } from '@angular/router';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';
 
@Component({
    moduleId: module.id,
    selector: 'create-item',
    providers: [CreateDataService],
    templateUrl: 'create.item.html',
    styles: ['.ng-valid[required], .ng-valid.required  {border-left: 5px solid #42A948; /* green */} .ng-invalid:not(form)  {border-left: 5px solid #a94442; /* red */} .h3Title{margin-top:0px;}']
})
 
export class CreateItemComponent {
 
    model = new createItemModule('', '');
 
    constructor(private _http: Http, private _router: Router, private _createDataService: CreateDataService) {
    }
 
    submitForm(form: any): void {
 
         this._ createDataService.createItem(form.name, form.number).subscribe(data => alert(data));
 
        this._router.navigateByUrl('/viewcomponent');
    }
}
  • Create new “html” file with name “create.item.html” inside “CreateItemComponent” folder.
  • Add below code in “create.item.html” file.
Create New HTML

This way you can create components for update and delete operation.

  • To implement routing Angular2 and to create Single Page Application, create new typescript file with name “app.routes.ts” in “app” folder. It will route components in angular application.
  • Add the below code in the “app.routes.ts” file.
import { Routes, RouterModule, provideRoutes } from '@angular/router';
import { AppComponent } from './app.component';
import { ViewComponent } from './viewComponent/view.component';
import { CreateItem } from './createItem/create.item';
import { DeleteComponent } from './deleteComponent/delete.component';
import { UpdateComponent } from './updateComponent/update.component';
 
export const routes: Routes = [
    { path: 'viewcomponent', component: ViewComponent },
    { path: '', redirectTo: '/viewcomponent', pathMatch: 'full' },
    { path: 'createitem', component: CreateItem },
    { path: 'updatecomponent', component: UpdateComponent },
    { path: 'deletecomponent', component: DeleteComponent }
];
export const routing = RouterModule.forRoot(routes);
  • Build the solution and publish the SharePoint app. Publish the web application.
  • Right click on web application project  click on “Open Folder in File Explorer”.
  • File Explorer window will be opened. Find and copy the folder “node_modules”  paste the folder in the published folder. We need to add this “node_modules” folder with the published code files in the hosting environment. As this folder contains all the typescript and JavaScript files dependencies.

Output

Output
Create New Item
profile-image
Vishal Shah

Vishal Shah has an extensive understanding of multiple application development frameworks and holds an upper hand with newer trends in order to strive and thrive in the dynamic market. He has nurtured his managerial growth in both technical and business aspects and gives his expertise through his blog posts.

Related Service

Know more about SharePoint development services

Learn more

Want to Hire Skilled Developers?


    Comments

    • Leave a message...