AngularJS – How to Use in SharePoint Framework (SPFx)

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

1.    Create SPFx Project with No JavaScript Web Framework

2.    Add Dev Dependencies

3.    Remove some Dependencies

4.    Run “npm install”

5.    Modify “config.json”

6.    Create folder called “app” under “/src/webparts/
angularjsWebpart/” and Create following files in “app” folder

a.       Greetings.component.html

b.       Greeting.module.css

c.       Greetings.component.ts

d.       Greetings.service.ts (If required)

e.       app.module.ts

7.       Modify “<<your_webpart>>webpart.ts” file & add some code.

8.       Finally run your solution

Create SPFx Project with No JavaScript Web Framework

Remember you have to create 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 creation of project, open this project in Visual Studio Code. Now open “package.json” and add following line of code in “devDependencies” section :

    “@types/angular”: “^1.6.57”,

    “@types/jquery”: “^3.3.31”,

    “@types/es6-promise”: “0.0.33”,

    “@types/webpack-env”: “1.13.1”,

    “sp-pnp-js”: “^3.0.10”

Here we are installing developer dependencies for AngularJS, Jquery & sp-pnp-js.

Remove some AngularJS Dependencies

Remove following code from “dependencies” section:

    “@types/es6-promise”: “0.0.33”,

    “@types/webpack-env”: “1.13.1”

Run “npm install”

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

Modify “config.json”

Now navigate to “config” folder and open “config.json” & modify “externals” section with following values :

"externals": {
    "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js",
    "angular": {
      "path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js",
      "globalName": "angular"
    },
    "es-promise": "https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.min.js",
    "fetch": "https://cdnjs.cloudflare.com/ajax/libs/fetch/3.0.0/fetch.js",
    "sp-pnp-js":"https://cdnjs.cloudflare.com/ajax/libs/sp-pnp-js/3.0.10/pnp.min.js"
  },

Create folder called “app” under “/src/webparts/angularjsWebpart /” and Create following files in “app” folder

Greetings.component.html

<div class="demo" ng-cloak>
  <div class="container">
      <div class="row">
          <div class="col-lg-12 col-md-12 col-sm-12">
              <div class="email-signature">
                  <div class="signature-img">
                      <img ng-src="{{$ctrl.userImageUrl}}" alt="">
                  </div>
                  <div class="signature-details">
                      <h3 class="title">{{$ctrl.userName}}</h3>
                      <span class="post">{{$ctrl.userJobTitle}}</span>
                  </div>
                  <ul class="signature-content">
                      <li><span class="fas fa-map-marker-alt"></span> {{$ctrl.greetingMessage}}</li>
                      <li><span class="fas fa-envelope"></span> {{$ctrl.webSiteTitle}}</li>
                  </ul>
              </div>
          </div>
      </div>
  </div>
</div>

Greeting.module.css

:root {
  --color_0: #000;
  --color_1: #fff;
  --name: #abb7c5;
  --shadow: rgba(0, 0, 0, 0.5);
  --main_bg: linear-gradient(to right, #181623 13%, #3c3b43 21%);
  --before_bg: linear-gradient(to bottom, #f9da41, #fa771c);
  --after_bg: linear-gradient(to bottom, #a2eee1, #1b819a);
  --main_bg_res: linear-gradient(to top, #181623 13%, #3c3b43 21%);
  --before_bg_res: linear-gradient(to right, #f9da41, #fa771c);
  --after_bg_res: linear-gradient(to right, #a2eee1, #1b819a);
}
.email-signature {
  background: var(--main_bg);
  font-family: "Roboto", sans-serif;
  padding: 20px 185px 20px 10px;
  box-shadow: 0 0 10px var(--shadow);
  position: relative;
  text-align: center;
}
.email-signature:before,
.email-signature:after {
  content: "";
  background: var(--before_bg);
  height: 100%;
  width: 100px;
  position: absolute;
  right: 0;
  top: 0;
}
.email-signature:after {
  background: var(--after_bg);
  width: 20px;
  right: 110px;
}
.email-signature .signature-img {
  height: 140px;
  width: 140px;
  border: 7px solid var(--color_1);
  border-radius: 25px;
  overflow: hidden;
  transform: translateY(-50%);
  position: absolute;
  right: 35px;
  top: 50%;
  z-index: 1;
}
.email-signature .signature-img img {
  width: 100%;
  height: auto;
}
.email-signature .signature-details {
  color: var(--name);
  font-size: 15px;
  margin-bottom: 20px;
  text-align: center;
}
.email-signature .title {
  font-size: 22px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 0;
  display: block;
}
.email-signature .title span {
  font-weight: 400;
}
.email-signature .signature-content {
  color: var(--color_1);
  font-size: 14px;
  line-height: 28px;
  padding: 0 0 0 20px;
  margin: 0;
  list-style: none;
}
.email-signature .signature-content li span {
  margin-right: 6px;
}
.email-signature .icon {
  background-color: var(--color_1);
  height: 100%;
  padding: 65px 30px;
  margin: 0;
  list-style: none;
  position: absolute;
  left: 0;
  top: 0;
}
.email-signature .icon li a {
  color: var(--color_1);
  background-color: var(--name);
  font-size: 16px;
  text-align: center;
  line-height: 25px;
  height: 25px;
  width: 25px;
  margin-bottom: 10px;
  display: block;
  transition: all 0.3s ease 0s;
}
.email-signature .icon li a:hover {
  color: var(--name);
  background-color: var(--color_0);
  text-decoration: none;
  box-shadow: 0 0 10px var(--shadow);
}
@media screen and (max-width: 767px) {
  .email-signature {
    background: var(--main_bg_res);
    text-align: center;
    padding: 175px 20px 70px 20px;
  }
  .email-signature .signature-img {
    transform: translateY(0) translateX(-50%);
    top: 20px;
    left: 50%;
  }
  .email-signature:before,
  .email-signature:after {
    background: var(--before_bg_res);
    width: 100%;
    height: 70px;
    transform: translateY(0);
    top: 0;
    left: 0;
  }
  .email-signature:after {
    background: var(--after_bg_res);
    height: 20px;
    top: 85px;
  }
  .email-signature .signature-details {
    margin: 0 0 5px 0;
  }
  .email-signature .signature-content {
    padding: 0;
  }
  .email-signature .icon {
    width: 100%;
    height: auto;
    padding: 15px 0;
    top: auto;
    bottom: 0;
  }
  .email-signature .icon li {
    display: inline-block;
  }
  .email-signature .icon li a {
    margin: 0 5px;
  }
}

Greetings.component.ts

import { GreetingService } from "./Greetings.service";

export class GreetingController {
  public userName: string = "";
  public userJobTitle: string = "";
  public webSiteTitle: string = "";
  public welComeMessage: string = "";
  public userImageUrl: string = "";

  public greetingMessage: string = "";
  public prefixWelcomeMessage: string = "Welcome to ";

  public static $inject: string[] = ["GreetingService", "$scope"];

  constructor(
    // tslint:disable-next-line: no-shadowed-variable
    private GreetingService: GreetingService,
    private $scope: ng.IScope
  ) {
    this.$scope.$on(
      "configurationChangedGreetingWebPart",
      (event: ng.IAngularEvent, data: any) => {
        this.webSiteTitle = data.webTitle;
        this.userName = data.userDisplayName;
        this.getValues();
        console.log(this.userImageUrl);
        //this.$scope.$apply();
      }
    );
    this.getValues();
  }

  public getValues = () => {
    if (new Date().getHours() > 0 && new Date().getHours() < 12)
      this.greetingMessage = "Good Morning ";
    else if (new Date().getHours() >= 12 && new Date().getHours() <= 5)
      this.greetingMessage = "Good Afternoon ";
    else if (new Date().getHours() > 5) this.greetingMessage = "Good Evening ";

    if (this.userName.length == 0) this.userName = "Gaurav Goyal";

    if (this.userJobTitle.length == 0) this.userJobTitle = "";

    if (this.webSiteTitle.length == 0)
      this.webSiteTitle = this.prefixWelcomeMessage + "Demo of SPFx Web Part";

    if (this.welComeMessage.length == 0)
      this.welComeMessage = this.greetingMessage + this.userName;

    // if (this.userImageUrl.length == 0)
    //   this.userImageUrl ="";

    this.getCurrentUserInformation();

  }

  public getCurrentUserInformation = () => {
    this.GreetingService.getCurrentUserInformation().then(ig => {
      this.webSiteTitle = this.prefixWelcomeMessage + this.webSiteTitle;
      this.userImageUrl = ig.userImageUrl;
      //this.userName = this.userName;
      this.userJobTitle = ig.userJobTitle;
      this.$scope.$apply();
    });
  }
}

export let GreetingComponent = {
  selector: "greetingComponent",
  template: require("./Greetings.component.html").toString(),
  bindings: {},
  controller: GreetingController,
  styles:require("./Greeting.module.css").toString()
};

Greetings.service.ts (If required)

import { IGreeting } from "./IGreeting";
//import * as angular from 'angular';
import * as $pnp from "sp-pnp-js";

export class GreetingService {
  constructor() {}

  public getCurrentUserInformation = (): Promise<IGreeting> => {
    let promise = new Promise<IGreeting>((resolve, reject) => {
      let ig: IGreeting = {
        userImageUrl: "",
        userJobTitle: "",
        userName: "",
        webSiteTitle: ""
      };

      $pnp.sp.profiles.myProperties.get().then(
        data => {
          data.UserProfileProperties.forEach(property => {
            if (property.Key == "Title") {
                ig.userJobTitle = property.Value;
            }

            if (property.Key == "PictureURL") {
              if(property.Value !==''){
                ig.userImageUrl = property.Value;}
              else{
                ig.userImageUrl = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png";
              }
              ig.userImageUrl = ig.userImageUrl.replace("MThumb", "LThumb");
            }
          });
          resolve(ig);
        },
        error => {
          reject(error);
        }
      );
    });
    return promise;
  }
}

app.module.ts

import * as angular from 'angular';
import {GreetingComponent, GreetingController} from './Greetings.component';
import { GreetingService } from './Greetings.service';

const greetingApp: angular.IModule = angular.module('greeting-webpart-app', []);

greetingApp
  .service("GreetingService", GreetingService);

greetingApp
   .controller('GreetingController', GreetingController);

  greetingApp
  .component(GreetingComponent.selector, GreetingComponent);

Modify “<<your_webpart>>webpart.ts” file & add some code.

At the top of the file, add 2 highlighted lines.

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 './GreetingsWebpartWebPart.module.scss';
import * as strings from 'GreetingsWebpartWebPartStrings';

export interface IGreetingsWebpartWebPartProps {
  description: string;
}

import * as angular from "angular";
import "./app/app.module";

Replace the render function:

public render(): void {

    if (this.renderedOnce === false) {
      this.domElement.innerHTML = `<greeting-component></greeting-component>`;
      this.$injector = angular.bootstrap(this.domElement, ["greeting-webpart-app"]);
    }

    let obj1={
      //webTitle, userDisplayName
      currentUserId: this.context.pageContext.legacyPageContext['userId'],
      webAbsoluteUrl: this.context.pageContext.legacyPageContext['webAbsoluteUrl'],
      webTitle: this.context.pageContext.legacyPageContext['webTitle'],
      userDisplayName: this.context.pageContext.legacyPageContext['userDisplayName'],
      tempData: this.properties.description
    };

    this.$injector.get("$rootScope").$broadcast("configurationChangedGreetingWebPart", obj1);
  }

Finally run your AngularJS solution

gulp serve –nobrowser
                run your sharepoint workbench
                                https://<<TenantName>>.sharepoint.com/_layouts/15/workbench.aspx
                                Add webpart & see the result

Want to learn more? Check out this post: SPFx: Using React Hooks to Globally Share Service Scope Between Components

Reference:

Goyal, G. (2020). How to Use AngularJS in SharePoint Framework (SPFx). Available at: http://sharepointgauravgoyal.blogspot.com/2020/05/how-to-use-angularjs-in-sharepoint.html [Accesed: 7th July 2020].

Share this on...

Rate this Post:

Share: