As we know Angular is one of the most powerful front-end development frameworks and SharePoint Framework is also a powerful feature in modern SharePoint.
So, in this article, we will see SharePoint framework integration with angular.
So let’s start with the environment setup.
Step 1: Create a SharePoint framework(SPFx) Webpart
First, We will create an SPFx webpart project using below command :
yo @microsoft/sharepoint
- This will ask you for following questions Which is your solution name? : Enter your solution name here
- Which baseline packages do you want to target for your component(s): Here we will select SharePoint Online online, you can select the option as per your requirement
- Where do you want to place the files? : We will use the current folder for this project.
Likewise this it will ask some more questions so we will give answers as below image
For more details refer to this article.
Step 2: Install Angular Dependencies in SPFx Project
Once SPFx Webpart is created we need to add required angular dependencies in package.json
- Update package.json file
You have to add the following packages into dependencies
property of package.json
.
"dependencies": { "@angular/common": "~4.0.0", "@angular/compiler": "~4.0.0", "@angular/core": "~4.0.0", "@angular/platform-browser": "~4.0.0", "@angular/platform-browser-dynamic": "~4.0.0", "@angular/router": "^4.0.0", "@microsoft/sp-core-library": "1.9.1", "@microsoft/sp-lodash-subset": "1.9.1", "@microsoft/sp-office-ui-fabric-core": "1.9.1", "@microsoft/sp-webpart-base": "1.9.1", "@types/es6-promise": "0.0.33", "@types/webpack-env": "1.13.1", "lodash": "^4.17.10", "reflect-metadata": "0.1.10", "rxjs": "~5.0.1", "systemjs": "0.19.40", "typescript-string-operations": "~1.1.0", "typings": "^2.1.1", "zone.js": "~0.8.4" }
After updating package.json
we have to execute npm install command to install angular dependencies.
npm install
2. Change tsconfig.json
Compare your current file with below and change accordingly.
{ "extends": "./node_modules/@microsoft/rush-stack-compiler-2.9/includes/tsconfig-web.json", "compilerOptions": { "target": "es5", "forceConsistentCasingInFileNames": true, "module": "commonjs", "jsx": "react", "declaration": true, "sourceMap": true, "experimentalDecorators": true, "skipLibCheck": true, "outDir": "lib", "inlineSources": false, "strictNullChecks": false, "noUnusedLocals": false, "typeRoots": ["./node_modules/@types", "./node_modules/@microsoft"], "types": ["webpack-env"], "lib": ["dom", "dom.iterable", "es2015", "scripthost"] }, "compileOnSave": false, "include": ["src/**/*.ts"], "exclude": ["node_modules", "lib"] }
Step 3: Implementation of Angular in SPFx
We will create Sample Angular application which includes the use of Angular Routing with SharePoint API Integration.
Sample Application Scenario: We want to create an angular app where we have two routes, users route, and groups route.
- Users route will show details about all Sharepoint site users.
- Groups route will show details about all Sharepoint site groups.
If you want to learn angular from scratch, refer here .
We will create a separate app
folder. All angular source files will be included here.
- Create a new folder app in the following hierarchy \\{{solution-directory}} > src > webparts > {{webpart-name}}.
- We will create the following files inside the app folder as we create in Angular.
app.module.ts
:AppModule
will be the root module for the angular app. We need to bootstrap this module in SPFx Webpart to render the angular application in SPFx.app.component.ts
:AppComponent
will be the root component, This will be initially rendered when an angular application gets started.AppComponent
is the parent component of all other angular components.app.component.html
: This is template file forAppComponent
, This file includes the navigation links and< router-outlet >
to render components based on the route.app-routing.module.ts
: We will configure application routes in separateAppRoutingModule
. We need to importAppRoutingModule
inAppModule
.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; @NgModule({ declarations: [ AppComponent ], imports: [BrowserModule, AppRoutingModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
import { Component } from '@angular/core'; @Component({ selector: "spfx-angular-app", template: require("./app.component.html") as string }) export class AppComponent { constructor() { } }
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ ]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule] }) export class AppRoutingModule { }
<h1 class="text-center text-primary">SPFx with Angular4 Routing</h1> <nav class="nav nav-tabs nav-stacked"> <a class="nav-link">Groups</a> <a class="nav-link">Users</a> </nav> <router-outlet></router-outlet>
3. Now as per our scenario we will create two components to render SharePoint site users and groups. for this, we will create
UsersComponent
inusers.component.ts
fileGroupsComponent
ingroups.component.ts
file
We have to declare both the component in AppModule
We will fetch SharePoint site users and groups using sp-pnp-js
the library . We can install it using the following command :
npm install sp-pnp-js
Once it is installed we will use in UsersComponent
and GroupsComponent
.
4. Once UsersComponent and GroupsComponent is created we will configure two routes /users
and /groups
in AppRoutingModule
as below
<div class="card border-info"> <div class="card-body"> <h4 class="card-title">Users</h4> <table class="table table-hover table-striped"> <thead> <tr> <th scope="col">Id</th> <th scope="col">Title</th> </tr> </thead> <tbody> <tr *ngFor="let u of users"> <td>{{ u.Id }}</td> <td>{{ u.Title }}</td> </tr> </tbody> </table> </div> </div>
<div class="card border-info"> <div class="card-body"> <h4 class="card-title">Groups</h4> <table class="table table-hover table-striped"> <thead> <tr> <th scope="col">Id</th> <th scope="col">Title</th> </tr> </thead> <tbody> <tr *ngFor="let g of groups"> <td>{{ g.Id }}</td> <td>{{ g.Title }}</td> </tr> </tbody> </table> </div> </div>
import { Component, OnInit } from '@angular/core'; import * as pnp from 'sp-pnp-js'; @Component({ selector: 'app-users', template: require('./users.component.html') }) export class UsersComponent implements OnInit { public title = 'Hello User'; public count = 0; public users: any = []; public ngOnInit() { this.users = []; pnp.sp.web.siteUsers .select("Id,Title") .get() .then(u => { this.users = u; }); } }
import { Component, OnInit } from '@angular/core'; import * as pnp from 'sp-pnp-js'; @Component({ selector: 'app-groups', template: require('./groups.component.html') }) export class GroupsComponent implements OnInit { public groups: any = []; public ngOnInit() { this.groups = []; pnp.sp.web.siteGroups .select("Id,Title,OwnerTitle") .get() .then(g => { this.groups = g; }); } }
Now we will update following files accordingly our requirement so our final code will be like this:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { GroupsComponent } from './groups/groups.component'; import { UsersComponent } from './users/users.component'; @NgModule({ declarations: [ AppComponent, GroupsComponent, UsersComponent ], imports: [BrowserModule, AppRoutingModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { GroupsComponent } from './groups/groups.component'; import { UsersComponent } from './users/users'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'users', pathMatch: 'full' }, { path: 'groups', component: GroupsComponent }, { path: 'users', component: UsersComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule] }) export class AppRoutingModule { } component'; @NgModule({ declarations: [ AppComponent, GroupsComponent, UsersComponent ], imports: [BrowserModule, AppRoutingModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
<h1 class="text-center text-primary">SPFx with Angular4 Routing</h1> <nav class="nav nav-tabs nav-stacked"> <a class="nav-link" routerLink="/groups" routerLinkActive="active">Groups</a> <a class="nav-link" routerLink="/users" routerLinkActive="active">Users</a> </nav> <router-outlet></router-outlet>
Now we will update [WebPartName]WebPart.ts
file as below
import "reflect-metadata"; require('zone.js'); import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { SPComponentLoader } from '@microsoft/sp-loader'; import { Version } from '@microsoft/sp-core-library'; import { IPropertyPaneConfiguration, PropertyPaneTextField } from '@microsoft/sp-property-pane'; import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; import { escape } from '@microsoft/sp-lodash-subset'; import styles from './SpFxAngular4RoutingWebPart.module.scss'; import * as strings from 'SpFxAngular4RoutingWebPartStrings'; export interface ISpFxAngular4RoutingWebPartProps { description: string; } export default class SpFxAngular4RoutingWebPart extends BaseClientSideWebPart <ISpFxAngular4RoutingWebPartProps> { public render(): void { let bootstrapCssUrl = "https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"; SPComponentLoader.loadCss(bootstrapCssUrl); this.domElement.innerHTML = '<spfx-angular-app>Loading...</spfx-angular-app>'; platformBrowserDynamic().bootstrapModule(AppModule); } protected get dataVersion(): Version { return Version.parse('1.0'); } protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField('description', { label: strings.DescriptionFieldLabel }) ] } ] } ] }; } }
Now we will serve this application using gulp serve
command.
This will serve your application on
SharePoint-SiteURL + /_layouts/15/workbench.aspx
Here you need to add created SPFx webpart in workbench.aspx
page.
This will give the following output.
Great ✨✨✨!!! Your SharePoint framework integration with Angular application is done.
You can find the complete source code of this application at end of article GitHub repository.
Output

GitHub Repository
https://github.com/chandaniprajapati/spfx-angular4-demo
If you like this project, mark a ⭐ on GitHub Repository
Summary
In this article we have seen, step by step implementation of SharePoint framework integration with Angular 4, We have also implemented Angular Routing in the sample application.
I hope you like this article, give your valuable feedback and suggestions in below comment section. If you have any doubts put it in the below comment section.
You may also like the following articles...
Sharing is Caring🙂.
Happy Coding👩💻.
Is it possible to insert this webpart into editor.aspx from some lista? The route is work fine?
Hi Gustavo Rost Machado,
Sorry for the late replay. Do you mean editform.aspx of the list?
Thanks.
How to impement this with Angular8?
Where have you created the Sharepoint Context ? I have run your code and it just says “Loading..”
Hi Rishi, are you running on localhost(workbench.html) or SharePoint workbench.apsx?
Hi Nishant, Thanks for your suggestion. Still, I haven’t created in Angular8 but you can follow the same step and let me know if you find any issue. I will work with angualr8 and share it.
Sharepoint workbench
I am new to SPFx , can you please guide me can we achieve the same using yo @pnp/spfx with angular elements in place. Currently yo @microsoft/sharepoint doesn’t not give OOB Angular.
Hi Rishi,
Sure.
Currently working on this. I will share it ASAP.