How to Use AngularJS in SharePoint Framework (SPFx)

Introduction 

 
In this post, I will show you how to use AngularJS in SPFx. I have divided the process into steps for better understanding. 

Steps

  • Create an SPFx Project without JavaScript Web Framework
  • Add Dev Dependencies
  • Remove some Dependencies
  • Run “npm install”
  • Modify “config.json”
  • Create a folder called “app” under “/src/webparts/ angularjsWebpart/” and create the following files in the “app” folder,

    • Greetings.component.html
    • Greeting.module.css
    • Greetings.component.ts
    • Greetings.service.ts (If required)
    • app.module.ts

  • Modify “<<your_webpart>>webpart.ts” file & add some code.
  • Finally, run your solution

Create an SPFx Project without JavaScript Web Framework

 
Remember that you have to create a project with No javascript web framework option.
 
Create a new project directory in your favorite location.
 
md angularjs-webpart
 
Go to the project directory.
 
cd angularjs-webpart
 
Create a new angularjs web part by running the Yeoman SharePoint Generator.
 
yo @microsoft/sharepoint
 
When prompted:
  • Accept the default angularjs-webpart as your solution name, and then select Enter.
  • Select SharePoint Online only (latest), and select Enter.
  • Select Use the current folder for where to place the files.
  • Select N to not allow the solution to be deployed to all sites immediately.
  • Select N on the question if solution contains unique permissions.
  • Select WebPart as the client-side component type to be created.
The next set of prompts ask for specific information about your web part:
  • Accept the default angularjs as your web part name, and then select Enter.
  • Accept the default angularjs description as your web part description, and then select Enter.
  • Accept the default No javascript web framework as the framework you would like to use, and then select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the angularjs web part. This might take a few minutes.
 
When the scaffold is complete, you should see the following message indicating a successful scaffold.
 

Add Dev Dependencies

 
After creating the project, open this in Visual Studio Code. Now open “package.json” and add the following line of code in the “devDependencies” section:
  1. "@types/angular""^1.6.57",  
  2. "@types/jquery""^3.3.31",  
  3. "@types/es6-promise""0.0.33",  
  4. "@types/webpack-env""1.13.1",  
  5. "sp-pnp-js""^3.0.10"  
Here, we are installing developer dependencies for AngularJS, Jquery & sp-pnp-js.
 

Remove Dependencies

 
Remove the following code from the “dependencies” section,
  1. "@types/es6-promise""0.0.33",  
  2. "@types/webpack-env""1.13.1"  

Run “npm install”

 
Now we have to run the npm install command to install dependencies in our project.
 

Modify “config.json”

 
Navigate to the “config” folder and open “config.json” & modify the “externals” section with the following values:
  1. "externals": {  
  2.     "jquery""https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js",  
  3.     "angular": {  
  4.         "path""https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js",  
  5.         "globalName""angular"  
  6.     },  
  7.     "es-promise""https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.min.js",  
  8.     "fetch""https://cdnjs.cloudflare.com/ajax/libs/fetch/3.0.0/fetch.js",  
  9.     "sp-pnp-js""https://cdnjs.cloudflare.com/ajax/libs/sp-pnp-js/3.0.10/pnp.min.js"  
  10. },  
Create a folder called “app” under “/src/webparts/angularjsWebpart /” and create the following files in the “app” folder,
 
Greetings.component.html
  1. <div class="demo" ng-cloak>  
  2.     <div class="container">  
  3.         <div class="row">  
  4.             <div class="col-lg-12 col-md-12 col-sm-12">  
  5.                 <div class="email-signature">  
  6.                     <div class="signature-img">  
  7.                         <img ng-src="{{$ctrl.userImageUrl}}" alt="">  
  8.                         </div>  
  9.                         <div class="signature-details">  
  10.                             <h3 class="title">{{$ctrl.userName}}</h3>  
  11.                             <span class="post">{{$ctrl.userJobTitle}}</span>  
  12.                         </div>  
  13.                         <ul class="signature-content">  
  14.                             <li>  
  15.                                 <span class="fas fa-map-marker-alt"></span> {{$ctrl.greetingMessage}}  
  16.                             </li>  
  17.                             <li>  
  18.                                 <span class="fas fa-envelope"></span> {{$ctrl.webSiteTitle}}  
  19.                             </li>  
  20.                         </ul>  
  21.                     </div>  
  22.                 </div>  
  23.             </div>  
  24.         </div>  
  25.     </div>  
Greeting.module.css
  1. :root {  
  2.   --color_0: #000;  
  3.   --color_1: #fff;  
  4.   --name: #abb7c5;  
  5.   --shadow: rgba(0000.5);  
  6.   --main_bg: linear-gradient(to right#181623 13%, #3c3b43 21%);  
  7.   --before_bg: linear-gradient(to bottom#f9da41#fa771c);  
  8.   --after_bg: linear-gradient(to bottom#a2eee1#1b819a);  
  9.   --main_bg_res: linear-gradient(to top#181623 13%, #3c3b43 21%);  
  10.   --before_bg_res: linear-gradient(to right#f9da41#fa771c);  
  11.   --after_bg_res: linear-gradient(to right#a2eee1#1b819a);  
  12. }  
  13.   
  14. .email-signature {  
  15.   background: var(--main_bg);  
  16.   font-family"Roboto"sans-serif;  
  17.   padding20px 185px 20px 10px;  
  18.   box-shadow: 0 0 10px var(--shadow);  
  19.   positionrelative;  
  20.   text-aligncenter;  
  21. }  
  22.   
  23. .email-signature:before,  
  24. .email-signature:after {  
  25.   content"";  
  26.   background: var(--before_bg);  
  27.   height100%;  
  28.   width100px;  
  29.   positionabsolute;  
  30.   right: 0;  
  31.   top: 0;  
  32. }  
  33.   
  34. .email-signature:after {  
  35.   background: var(--after_bg);  
  36.   width20px;  
  37.   right: 110px;  
  38. }  
  39.   
  40. .email-signature .signature-img {  
  41.   height140px;  
  42.   width140px;  
  43.   border7px solid var(--color_1);  
  44.   border-radius: 25px;  
  45.   overflowhidden;  
  46.   transform: translateY(-50%);  
  47.   positionabsolute;  
  48.   right: 35px;  
  49.   top: 50%;  
  50.   z-index1;  
  51. }  
  52.   
  53. .email-signature .signature-img img {  
  54.   width100%;  
  55.   heightauto;  
  56. }  
  57.   
  58. .email-signature .signature-details {  
  59.   color: var(--name);  
  60.   font-size15px;  
  61.   margin-bottom20px;  
  62.   text-aligncenter;  
  63. }  
  64.   
  65. .email-signature .title {  
  66.   font-size22px;  
  67.   font-weight600;  
  68.   text-transformuppercase;  
  69.   letter-spacing1px;  
  70.   margin0;  
  71.   displayblock;  
  72. }  
  73.   
  74. .email-signature .title span {  
  75.   font-weight400;  
  76. }  
  77.   
  78. .email-signature .signature-content {  
  79.   color: var(--color_1);  
  80.   font-size14px;  
  81.   line-height28px;  
  82.   padding0 0 0 20px;  
  83.   margin0;  
  84.   list-stylenone;  
  85. }  
  86.   
  87. .email-signature .signature-content li span {  
  88.   margin-right6px;  
  89. }  
  90.   
  91. .email-signature .icon {  
  92.   background-color: var(--color_1);  
  93.   height100%;  
  94.   padding65px 30px;  
  95.   margin0;  
  96.   list-stylenone;  
  97.   positionabsolute;  
  98.   left: 0;  
  99.   top: 0;  
  100. }  
  101.   
  102. .email-signature .icon li a {  
  103.   color: var(--color_1);  
  104.   background-color: var(--name);  
  105.   font-size16px;  
  106.   text-aligncenter;  
  107.   line-height25px;  
  108.   height25px;  
  109.   width25px;  
  110.   margin-bottom10px;  
  111.   displayblock;  
  112.   transition: all 0.3s ease 0s;  
  113. }  
  114.   
  115. .email-signature .icon li a:hover {  
  116.   color: var(--name);  
  117.   background-color: var(--color_0);  
  118.   text-decorationnone;  
  119.   box-shadow: 0 0 10px var(--shadow);  
  120. }  
  121.   
  122. @media screen and (max-width767px) {  
  123.   .email-signature {  
  124.     background: var(--main_bg_res);  
  125.     text-aligncenter;  
  126.     padding175px 20px 70px 20px;  
  127.   }  
  128.   
  129.   .email-signature .signature-img {  
  130.     transform: translateY(0) translateX(-50%);  
  131.     top: 20px;  
  132.     left: 50%;  
  133.   }  
  134.   
  135.   .email-signature:before,  
  136. .email-signature:after {  
  137.     background: var(--before_bg_res);  
  138.     width100%;  
  139.     height70px;  
  140.     transform: translateY(0);  
  141.     top: 0;  
  142.     left: 0;  
  143.   }  
  144.   
  145.   .email-signature:after {  
  146.     background: var(--after_bg_res);  
  147.     height20px;  
  148.     top: 85px;  
  149.   }  
  150.   
  151.   .email-signature .signature-details {  
  152.     margin0 0 5px 0;  
  153.   }  
  154.   
  155.   .email-signature .signature-content {  
  156.     padding0;  
  157.   }  
  158.   
  159.   .email-signature .icon {  
  160.     width100%;  
  161.     heightauto;  
  162.     padding15px 0;  
  163.     top: auto;  
  164.     bottom: 0;  
  165.   }  
  166.   
  167.   .email-signature .icon li {  
  168.     display: inline-block;  
  169.   }  
  170.   
  171.   .email-signature .icon li a {  
  172.     margin0 5px;  
  173.   }  
  174. }  
Greetings.component.ts
  1. import {  
  2.     GreetingService  
  3. } from "./Greetings.service";  
  4. export class GreetingController {  
  5.     public userName: string = "";  
  6.     public userJobTitle: string = "";  
  7.     public webSiteTitle: string = "";  
  8.     public welComeMessage: string = "";  
  9.     public userImageUrl: string = "";  
  10.     public greetingMessage: string = "";  
  11.     public prefixWelcomeMessage: string = "Welcome to ";  
  12.     public static $inject: string[] = ["GreetingService""$scope"];  
  13.     constructor(  
  14.         // tslint:disable-next-line: no-shadowed-variable  
  15.         private GreetingService: GreetingService, private $scope: ng.IScope) {  
  16.         this.$scope.$on("configurationChangedGreetingWebPart",  
  17.             (event: ng.IAngularEvent, data: any) => {  
  18.                 this.webSiteTitle = data.webTitle;  
  19.                 this.userName = data.userDisplayName;  
  20.                 this.getValues();  
  21.                 console.log(this.userImageUrl);  
  22.                 //this.$scope.$apply();  
  23.             });  
  24.         this.getValues();  
  25.     }  
  26.     public getValues = () => {  
  27.         if (new Date().getHours() > 0 && new Date().getHours() < 12) this.greetingMessage = "Good Morning ";  
  28.         else if (new Date().getHours() >= 12 && new Date().getHours() <= 5) this.greetingMessage = "Good Afternoon ";  
  29.         else if (new Date().getHours() > 5) this.greetingMessage = "Good Evening ";  
  30.         if (this.userName.length == 0) this.userName = "Gaurav Goyal";  
  31.         if (this.userJobTitle.length == 0) this.userJobTitle = "";  
  32.         if (this.webSiteTitle.length == 0) this.webSiteTitle = this.prefixWelcomeMessage + "Demo of SPFx Web Part";  
  33.         if (this.welComeMessage.length == 0) this.welComeMessage = this.greetingMessage + this.userName;  
  34.         // if (this.userImageUrl.length == 0)  
  35.         // this.userImageUrl ="";  
  36.         this.getCurrentUserInformation();  
  37.     }  
  38.     public getCurrentUserInformation = () => {  
  39.         this.GreetingService.getCurrentUserInformation().then(ig => {  
  40.             this.webSiteTitle = this.prefixWelcomeMessage + this.webSiteTitle;  
  41.             this.userImageUrl = ig.userImageUrl;  
  42.             //this.userName = this.userName;  
  43.             this.userJobTitle = ig.userJobTitle;  
  44.             this.$scope.$apply();  
  45.         });  
  46.     }  
  47. }  
  48. export let GreetingComponent = {  
  49.     selector: "greetingComponent",  
  50.     template: require("./Greetings.component.html").toString(),  
  51.     bindings: {},  
  52.     controller: GreetingController,  
  53.     styles: require("./Greeting.module.css").toString()  
  54. };  
Greetings.service.ts (If required)
  1. import {  
  2.     IGreeting  
  3. } from "./IGreeting";  
  4. //import * as angular from 'angular';  
  5. import * as $pnp from "sp-pnp-js";  
  6. export class GreetingService {  
  7.     constructor() {}  
  8.     public getCurrentUserInformation = (): Promise < IGreeting > => {  
  9.         let promise = new Promise < IGreeting > ((resolve, reject) => {  
  10.             let ig: IGreeting = {  
  11.                 userImageUrl: "",  
  12.                 userJobTitle: "",  
  13.                 userName: "",  
  14.                 webSiteTitle: ""  
  15.             };  
  16.             $pnp.sp.profiles.myProperties.get().then(data => {  
  17.                 data.UserProfileProperties.forEach(property => {  
  18.                     if (property.Key == "Title") {  
  19.                         ig.userJobTitle = property.Value;  
  20.                     }  
  21.                     if (property.Key == "PictureURL") {  
  22.                         if (property.Value !== '') {  
  23.                             ig.userImageUrl = property.Value;  
  24.                         } else {  
  25.                             ig.userImageUrl = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png";  
  26.                         }  
  27.                         ig.userImageUrl = ig.userImageUrl.replace("MThumb""LThumb");  
  28.                     }  
  29.                 });  
  30.                 resolve(ig);  
  31.             }, error => {  
  32.                 reject(error);  
  33.             });  
  34.         });  
  35.         return promise;  
  36.     }  
  37. }  
app.module.ts
  1. import * as angular from 'angular';  
  2. import {GreetingComponent, GreetingController} from './Greetings.component';  
  3. import { GreetingService } from './Greetings.service';  
  4. const greetingApp: angular.IModule = angular.module('greeting-webpart-app', []);  
  5. greetingApp  
  6. .service("GreetingService", GreetingService);  
  7. greetingApp  
  8. .controller('GreetingController', GreetingController);  
  9. greetingApp  
  10. .component(GreetingComponent.selector, GreetingComponent);  
Modify “<<your_webpart>>webpart.ts” file & add some code.
 
At the top of the file, add 2 highlighted lines.
  1. import { Version } from '@microsoft/sp-core-library';  
  2. import {  
  3.    IPropertyPaneConfiguration,  
  4.    PropertyPaneTextField  
  5.    } from '@microsoft/sp-property-pane';  
  6. import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';  
  7. import { escape } from '@microsoft/sp-lodash-subset';  
  8. import styles from './GreetingsWebpartWebPart.module.scss';  
  9. import * as strings from 'GreetingsWebpartWebPartStrings';  
  10. export interface IGreetingsWebpartWebPartProps {  
  11.    description: string;  
  12.    }  
  13. import * as angular from "angular";  
  14. import "./app/app.module";  
Replace the render function:
  1. public render(): void {  
  2.     if (this.renderedOnce === false) {  
  3.         this.domElement.innerHTML = `<greeting-component></greeting-component>`;  
  4.         this.$injector = angular.bootstrap(this.domElement, ["greeting-webpart-app"]);  
  5.     }  
  6.     let obj1 = {  
  7.         //webTitle, userDisplayName  
  8.         currentUserId: this.context.pageContext.legacyPageContext['userId'],  
  9.         webAbsoluteUrl: this.context.pageContext.legacyPageContext['webAbsoluteUrl'],  
  10.         webTitle: this.context.pageContext.legacyPageContext['webTitle'],  
  11.         userDisplayName: this.context.pageContext.legacyPageContext['userDisplayName'],  
  12.         tempData: this.properties.description  
  13.     };  
  14.     this.$injector.get("$rootScope").$broadcast("configurationChangedGreetingWebPart", obj1);  
  15. }  
Finally, run your solution.
 
gulp serve –nobrowser
 
Run your Sharepoint workbench.
 
https://<<TenantName>>.sharepoint.com/_layouts/15/workbench.aspx
 
Add webpart & see the result.
 
My sample code is part of the PnP community - SPFx Dev webpart sample. Click here to download the code.
 
Output
 
How To Use AngularJS In SharePoint Framework (SPFx)