Open your command-line interface (CLI), navigate to a directory where you have rights to create files, and run the following commands to install the Angular CLI tool and create a new Angular app.
npm install -g @angular/cli
ng new graph-tutorialThe Angular CLI will prompt for more information. Answer the prompts as follows.
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSSOnce the command finishes, change to the graph-tutorial directory in your CLI and run the following command to start a local web server.
ng serve --openYour default browser opens to https://localhost:4200/ with a default Angular page. If your browser doesn't open, open it and browse to https://localhost:4200/ to verify that the new app works.
Before moving on, install some additional packages that you will use later:
- bootstrap for styling and common components.
- ng-bootstrap for using Bootstrap components from Angular.
- angular-fontawesome to use FontAwesome icons in Angular.
- fontawesome-svg-core, free-regular-svg-icons, and free-solid-svg-icons for the FontAwesome icons used in the sample.
- moment for formatting dates and times.
- msal-angular for authenticating to Azure Active Directory and retrieving access tokens.
- rxjs-compat, required for the
msal-angularpackage. - microsoft-graph-client for making calls to Microsoft Graph.
Run the following command in your CLI.
npm install bootstrap@4.3.1 @fortawesome/angular-fontawesome@0.3.0 @fortawesome/fontawesome-svg-core@1.2.17
npm install @fortawesome/free-regular-svg-icons@5.8.1 @fortawesome/free-solid-svg-icons@5.8.1
npm install moment@2.24.0 moment-timezone@0.5.25 @ng-bootstrap/ng-bootstrap@4.1.2
npm install @azure/msal-angular@0.1.2 rxjs-compat@6.5.1 @microsoft/microsoft-graph-client@1.6.0Start by adding the Bootstrap CSS files to the app, as well as some global styles. Open the ./src/styles.css and add the following lines.
@import "~bootstrap/dist/css/bootstrap.css";
/* Add padding for the nav bar */
body {
padding-top: 4.5rem;
}
/* Style debug info in alerts */
.alert-pre {
word-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
}Next, add the Bootstrap and FontAwesome modules to the app. Open ./src/app/app.module.ts and add the following import statements to the top of the file.
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import { faUserCircle } from '@fortawesome/free-regular-svg-icons';Then add the following code after all of the import statements.
library.add(faExternalLinkAlt);
library.add(faUserCircle);In the @NgModule declaration, replace the existing imports array with the following.
imports: [
BrowserModule,
AppRoutingModule,
NgbModule,
FontAwesomeModule
]Now generate an Angular component for the top navigation on the page. In your CLI, run the following command.
ng generate component nav-barOnce the command completes, open the ./src/app/nav-bar/nav-bar.component.ts file and replace its contents with the following.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-nav-bar',
templateUrl: './nav-bar.component.html',
styleUrls: ['./nav-bar.component.css']
})
export class NavBarComponent implements OnInit {
// Should the collapsed nav show?
showNav: boolean;
// Is a user logged in?
authenticated: boolean;
// The user
user: any;
constructor() { }
ngOnInit() {
this.showNav = false;
this.authenticated = false;
this.user = {};
}
// Used by the Bootstrap navbar-toggler button to hide/show
// the nav in a collapsed state
toggleNavBar(): void {
this.showNav = !this.showNav;
}
signIn(): void {
// Temporary
this.authenticated = true;
this.user = {
displayName: 'Adele Vance',
email: 'AdeleV@contoso.com'
};
}
signOut(): void {
// Temporary
this.authenticated = false;
this.user = {};
}
}Open the ./src/app/nav-bar/nav-bar.component.html file and replace its contents with the following.
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container">
<a routerLink="/" class="navbar-brand">Angular Graph Tutorial</a>
<button class="navbar-toggler" type="button" (click)="toggleNavBar()" [attr.aria-expanded]="showNav"
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" [class.show]="showNav" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a routerLink="/" class="nav-link" routerLinkActive="active">Home</a>
</li>
<li *ngIf="authenticated" class="nav-item">
<a routerLink="/calendar" class="nav-link" routerLinkActive="active">Calendar</a>
</li>
</ul>
<ul class="navbar-nav justify-content-end">
<li class="nav-item">
<a class="nav-link" href="https://docs.microsoft.com/graph/overview" target="_blank">
<fa-icon [icon]="[ 'fas', 'external-link-alt' ]" class="mr-1"></fa-icon>Docs
</a>
</li>
<li *ngIf="authenticated" ngbDropdown placement="bottom-right" class="nav-item">
<a ngbDropdownToggle id="userMenu" class="nav-link" href="javascript:undefined" role="button" aria-haspopup="true"
aria-expanded="false">
<div *ngIf="user.avatar; then userAvatar else defaultAvatar"></div>
<ng-template #userAvatar>
<img src="user.avatar" class="rounded-circle align-self-center mr-2" style="width: 32px;">
</ng-template>
<ng-template #defaultAvatar>
<fa-icon [icon]="[ 'far', 'user-circle' ]" fixedWidth="true" size="lg"
class="rounded-circle align-self-center mr-2"></fa-icon>
</ng-template>
</a>
<div ngbDropdownMenu aria-labelledby="userMenu">
<h5 class="dropdown-item-text mb-0">{{user.displayName}}</h5>
<p class="dropdown-item-text text-muted mb-0">{{user.email}}</p>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="javascript:undefined" role="button" (click)="signOut()">Sign Out</a>
</div>
</li>
<li *ngIf="!authenticated" class="nav-item">
<a class="nav-link" href="javascript:undefined" role="button" (click)="signIn()">Sign In</a>
</li>
</ul>
</div>
</div>
</nav>Next, create a home page for the app. Run the following command in your CLI.
ng generate component homeOnce the command completes, open the ./src/app/home/home.component.ts file and replace its contents with the following.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
// Is a user logged in?
authenticated: boolean;
// The user
user: any;
constructor() { }
ngOnInit() {
this.authenticated = false;
this.user = {};
}
signIn(): void {
// Temporary
this.authenticated = true;
this.user = {
displayName: 'Adele Vance',
email: 'AdeleV@contoso.com'
};
}
}Then open the ./src/app/home/home.component.html file and replace its contents with the following.
<div class="jumbotron">
<h1>Angular Graph Tutorial</h1>
<p class="lead">This sample app shows how to use the Microsoft Graph API from Angular</p>
<div *ngIf="authenticated; then welcomeUser else signInPrompt"></div>
<ng-template #welcomeUser>
<h4>Welcome {{ user.displayName }}!</h4>
<p>Use the navigation bar at the top of the page to get started.</p>
</ng-template>
<ng-template #signInPrompt>
<a href="javascript:undefined" class="btn btn-primary btn-large" role="button" (click)="signIn()">Click here to sign in</a>
</ng-template>
</div>Now create an alert service that the app can use to display messages to the user. Start by creating a simple Alert class. Create a new file in the ./src/app directory named alert.ts and add the following code.
export class Alert {
message: string;
debug: string;
}In your CLI, run the following command.
ng generate service alertsOpen the ./src/app/alerts.service.ts file and replace its contents with the following.
import { Injectable } from '@angular/core';
import { Alert } from './alert';
@Injectable({
providedIn: 'root'
})
export class AlertsService {
alerts: Alert[] = [];
add(message: string, debug: string) {
this.alerts.push({message: message, debug: debug});
}
remove(alert: Alert) {
this.alerts.splice(this.alerts.indexOf(alert), 1);
}
}Now generate an alerts component to display alerts. In your CLI, run the following command.
ng generate component alertsOnce the command completes, open the ./src/app/alerts/alerts.component.ts file and replace its contents with the following.
import { Component, OnInit } from '@angular/core';
import { AlertsService } from '../alerts.service';
import { Alert } from '../alert';
@Component({
selector: 'app-alerts',
templateUrl: './alerts.component.html',
styleUrls: ['./alerts.component.css']
})
export class AlertsComponent implements OnInit {
constructor(private alertsService: AlertsService) { }
ngOnInit() {
}
close(alert: Alert) {
this.alertsService.remove(alert);
}
}Then open the ./src/app/alerts/alerts.component.html file and replace its contents with the following.
<div *ngFor="let alert of alertsService.alerts">
<ngb-alert type="danger" (close)="close(alert)">
<p>{{alert.message}}</p>
<pre *ngIf="alert.debug" class="alert-pre border bg-light p-2"><code>{{alert.debug}}</code></pre>
</ngb-alert>
</div>Now with those basic components defined, update the app to use them. First, open the ./src/app/app-routing.module.ts file and replace the const routes: Routes = []; line with the following code.
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
];Open the ./src/app/app.component.html file and replace its entire contents with the following.
<app-nav-bar></app-nav-bar>
<main role="main" class="container">
<app-alerts></app-alerts>
<router-outlet></router-outlet>
</main>Save all of your changes and refresh the page. Now, the app should look very different.
