Créez des applications Angular à une seule page avec Microsoft Graph
Ce didacticiel vous apprend à créer une application Angular page unique qui utilise Microsoft Graph pour récupérer les informations de calendrier d’un utilisateur.
Conseil
Si vous préférez simplement télécharger le didacticiel terminé, vous pouvez télécharger ou cloner le GitHub complet.
Conditions préalables
Avant de commencer ce didacticiel, vous devez avoir installéNode.js sur votre ordinateur de développement. Si vous n’avez pas Node.js, consultez le lien précédent pour obtenir les options de téléchargement.
Vous devez également avoir un compte Microsoft personnel avec une boîte aux lettres sur Outlook.com, ou un compte scolaire ou scolaire Microsoft. Si vous n’avez pas de compte Microsoft, deux options s’offrent à vous pour obtenir un compte gratuit :
- Vous pouvez vous inscrire à un nouveau compte Microsoft personnel.
- Vous pouvez vous inscrire au programme Microsoft 365 développeur pour obtenir un abonnement Office 365 gratuit.
Notes
Ce didacticiel a été écrit avec Node version 14.15.0. Les étapes de ce guide peuvent fonctionner avec d’autres versions, mais elles n’ont pas été testées.
Commentaires
N’hésitez pas à nous faire part de vos commentaires sur ce didacticiel dans GitHub référentiel.
Créer une application Angular d’une seule page
Dans cette section, vous allez créer un projet Angular projet.
Ouvrez votre interface de ligne de commande (CLI), accédez à un répertoire dans lequel vous avez le droit de créer des fichiers, puis exécutez les commandes suivantes pour installer l’outil CLI Angular et créer une application Angular.
npm install -g @angular/cli ng new graph-tutorial
La Angular CLI vous invite à fournir plus d’informations. Répondez aux invites comme suit.
? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
Une fois la commande terminé, modifiez
graph-tutorial
le répertoire dans votre CLI et exécutez la commande suivante pour démarrer un serveur web local.ng serve --open
Votre navigateur par défaut s’ouvre avec https://localhost:4200/ une page de Angular par défaut. Si votre navigateur ne s’ouvre pas, ouvrez-le https://localhost:4200/ et recherchez-le pour vérifier que la nouvelle application fonctionne.
Ajouter des packages de nœuds
Avant de passer à la suite, installez des packages supplémentaires que vous utiliserez ultérieurement :
- ng-bootstrap pour utiliser des composants Bootstrap à partir de Angular.
- moment de mise en forme des dates et heures.
- windows-iana
- msal-angular pour l’authentification auprès Azure Active Directory et la récupération des jetons d’accès.
- microsoft-graph-client pour effectuer des appels à Microsoft Graph.
Exécutez les commandes suivantes dans votre CLI.
ng add @ng-bootstrap/ng-bootstrap npm install @azure/msal-browser@2.16.1 @azure/msal-angular@2.0.2 npm install date-fns@2.23.0 date-fns-tz@1.1.6 windows-iana@5.0.2 npm install @microsoft/microsoft-graph-client@3.0.0 npm install @microsoft/microsoft-graph-types --save-dev
Concevoir l’application
Dans cette section, vous allez créer l’interface utilisateur de l’application.
Ouvrez ./src/styles.css et ajoutez les lignes suivantes.
@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; } /* Add padding to user avatar link */ .avatar-link { padding-top: .25em; padding-bottom: .25em; }
Créez un fichier dans le dossier ./src/app nommé user.ts et ajoutez le code suivant.
export class User { displayName!: string; email!: string; avatar!: string; timeZone!: string; }
Générez un Angular pour la navigation supérieure sur la page. Dans votre CLI, exécutez la commande suivante.
ng generate component nav-bar
Une fois la commande terminée, ouvrez ./src/app/nav-bar/nav-bar.component.ts et remplacez son contenu par ce qui suit.
import { Component, OnInit } from '@angular/core'; import { User } from '../user'; @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 = false; // Is a user logged in? authenticated: boolean = false; // The user user?: User = undefined; constructor() { } ngOnInit() { } // 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', avatar: '/assets/no-profile-photo.png', timeZone: '' }; } signOut(): void { // Temporary this.authenticated = false; this.user = undefined; } }
Ouvrez ./src/app/nav-bar/nav-bar.component.html et remplacez son contenu par ce qui suit.
<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">Docs</a> </li> <li *ngIf="authenticated" ngbDropdown placement="bottom-right" class="nav-item"> <a ngbDropdownToggle id="userMenu" class="nav-link avatar-link" role="button" aria-haspopup="true" aria-expanded="false"> <img src="{{user != null ? user.avatar : ''}}" class="rounded-circle align-self-center mr-2" style="width: 32px;"> </a> <div ngbDropdownMenu aria-labelledby="userMenu" class="dropdown-menu-right"> <h5 class="dropdown-item-text mb-0">{{user != null ? user.displayName : ''}}</h5> <p class="dropdown-item-text text-muted mb-0">{{user != null ? user.email : ''}}</p> <div class="dropdown-divider"></div> <button class="dropdown-item" role="button" (click)="signOut()">Sign Out</button> </div> </li> <li *ngIf="!authenticated" class="nav-item"> <button class="btn btn-link nav-link border-0" role="button" (click)="signIn()">Sign In</button> </li> </ul> </div> </div> </nav>
Créez une page d’accueil pour l’application. Exécutez la commande suivante dans votre CLI.
ng generate component home
Une fois la commande terminée, ouvrez ./src/app/home/home.component.ts et remplacez son contenu par ce qui suit.
import { Component, OnInit } from '@angular/core'; import { User } from '../user'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { // Is a user logged in? authenticated: boolean = false; // The user user?: User = undefined; constructor() { } ngOnInit() { } signIn(): void { // Temporary this.authenticated = true; this.user = { displayName: 'Adele Vance', email: 'AdeleV@contoso.com', avatar: '', timeZone: '' }; } }
Ouvrez ./src/app/home/home.component.html et remplacez son contenu par ce qui suit.
<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 != null ? user.displayName : '' }}!</h4> <p>Use the navigation bar at the top of the page to get started.</p> </ng-template> <ng-template #signInPrompt> <button class="btn btn-primary btn-large" role="button" (click)="signIn()">Click here to sign in</button> </ng-template> </div>
Créez une classe simple
Alert
. Créez un fichier dans le répertoire ./src/app nommé alert.ts et ajoutez le code suivant.export class Alert { type!: string; message!: string; debug!: string; }
Créez un service d’alerte que l’application peut utiliser pour afficher des messages à l’utilisateur. Dans votre CLI, exécutez la commande suivante.
ng generate service alerts
Ouvrez ./src/app/alerts.service.ts et remplacez son contenu par ce qui suit.
import { Injectable } from '@angular/core'; import { Alert } from './alert'; @Injectable({ providedIn: 'root' }) export class AlertsService { alerts: Alert[] = []; addError(message: string, debug?: string) { this.alerts.push({message: message, debug: debug ?? '', type: 'danger'}); } addSuccess(message: string, debug?: string) { this.alerts.push({message: message, debug: debug ?? '', type: 'success'}); } remove(alert: Alert) { this.alerts.splice(this.alerts.indexOf(alert), 1); } }
Générer un composant d’alertes pour afficher les alertes. Dans votre CLI, exécutez la commande suivante.
ng generate component alerts
Une fois la commande terminée, ouvrez ./src/app/alerts/alerts.component.ts et remplacez son contenu par ce qui suit.
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(public alertsService: AlertsService) { } ngOnInit() { } close(alert: Alert) { this.alertsService.remove(alert); } }
Ouvrez ./src/app/alerts/alerts.component.html et remplacez son contenu par ce qui suit.
<div *ngFor="let alert of alertsService.alerts"> <ngb-alert type="{{alert.type}}" (close)="close(alert)"> {{alert.message}} <pre *ngIf="alert.debug" class="alert-pre border bg-light p-2 mt-2"><code>{{alert.debug}}</code></pre> </ngb-alert> </div>
Ouvrez ./src/app/app-routing.module.ts et remplacez
const routes: Routes = [];
la ligne par le code suivant.import { HomeComponent } from './home/home.component'; const routes: Routes = [ { path: '', component: HomeComponent }, ];
Ouvrez ./src/app/app.component.html et remplacez tout son contenu par ce qui suit.
<app-nav-bar></app-nav-bar> <main role="main" class="container"> <app-alerts></app-alerts> <router-outlet></router-outlet> </main>
Ajoutez un fichier image de votre choixno-profile-photo.png **** dans le répertoire ./src/assets . Cette image est utilisée comme photo de l’utilisateur lorsque l’utilisateur n’a pas de photo dans Microsoft Graph.
Enregistrez toutes vos modifications et actualisez la page. L’application doit maintenant avoir une apparence très différente.
Inscrire l’application sur le portail
Dans cet exercice, vous allez créer une nouvelle inscription Azure AD’application web à l’aide du centre d Azure Active Directory’administration.
Ouvrez un navigateur et accédez au Centre d’administration Azure Active Directory. Connectez-vous à l’aide d’un compte personnel (compte Microsoft) ou d’un compte professionnel ou scolaire.
Sélectionnez Azure Active Directory dans le volet de navigation gauche, puis sélectionnez Inscriptions d’applications sous Gérer.
Sélectionnez Nouvelle inscription. Sur la page Inscrire une application, définissez les valeurs comme suit.
- Définissez le Nom sur
Angular Graph Tutorial
. - Définissez les Types de comptes pris en charge sur Comptes dans un annuaire organisationnel et comptes personnels Microsoft.
- Sous URI de redirection, définissez la première flèche déroulante sur
Single-page application (SPA)
, et la valeur surhttp://localhost:4200
.
- Définissez le Nom sur
Sélectionner Inscription. Dans la page Angular Graph didacticiel, copiez la valeur de l’ID de l’application (client) et enregistrez-la. Vous en aurez besoin à l’étape suivante.
Ajouter une authentification Azure AD
Dans cet exercice, vous allez étendre l’application de l’exercice précédent pour prendre en charge l’authentification avec Azure AD. Cette étape est nécessaire pour obtenir le jeton d’accès OAuth nécessaire pour appeler l’Graph Microsoft. Dans cette étape, vous allez intégrer la bibliothèque d’authentification Microsoft Angular dans l’application.
Créez un fichier dans le répertoire ./src nommé oauth.ts et ajoutez le code suivant.
export const OAuthSettings = { appId: 'YOUR_APP_ID_HERE', redirectUri: 'http://localhost:4200', scopes: [ "user.read", "mailboxsettings.read", "calendars.readwrite" ] };
Remplacez-le
YOUR_APP_ID_HERE
par l’ID de l’application à partir du portail d’inscription des applications.Important
Si vous utilisez un contrôle source tel que Git, il est temps d’exclure le fichier oauth.ts du contrôle source afin d’éviter toute fuite accidentelle de votre ID d’application.
Ouvrez ./src/app/app.module.ts
import
et ajoutez les instructions suivantes en haut du fichier.import { FormsModule } from '@angular/forms'; import { IPublicClientApplication, PublicClientApplication, BrowserCacheLocation } from '@azure/msal-browser'; import { MsalModule, MsalService, MSAL_INSTANCE } from '@azure/msal-angular'; import { OAuthSettings } from '../oauth';
Ajoutez la fonction suivante sous les
import
instructions.let msalInstance: IPublicClientApplication | undefined = undefined; export function MSALInstanceFactory(): IPublicClientApplication { msalInstance = msalInstance ?? new PublicClientApplication({ auth: { clientId: OAuthSettings.appId, redirectUri: OAuthSettings.redirectUri, postLogoutRedirectUri: OAuthSettings.redirectUri }, cache: { cacheLocation: BrowserCacheLocation.LocalStorage, } }); return msalInstance; }
Ajouter
MsalModule
et ajouterFormsModule
au tableau àimports
l’intérieur de la@NgModule
déclaration.imports: [ BrowserModule, FormsModule, AppRoutingModule, NgbModule, MsalModule ],
Ajoutez le
MSALInstanceFactory
tableau etMsalService
le tableauproviders
à l’intérieur de la@NgModule
déclaration.providers: [ { provide: MSAL_INSTANCE, useFactory: MSALInstanceFactory }, MsalService ],
Implémentation de la connexion
Dans cette section, vous allez créer un service d’authentification et implémenter la sign-in et la sign-out.
Exécutez la commande suivante dans votre CLI.
ng generate service auth
En créant un service pour cela, vous pouvez facilement l’injecter dans tous les composants qui ont besoin d’accéder aux méthodes d’authentification.
Une fois la commande terminé, ouvrez ./src/app/auth.service.ts et remplacez son contenu par le code suivant.
import { Injectable } from '@angular/core'; import { MsalService } from '@azure/msal-angular'; import { InteractionType, PublicClientApplication } from '@azure/msal-browser'; import { AlertsService } from './alerts.service'; import { OAuthSettings } from '../oauth'; import { User } from './user'; @Injectable({ providedIn: 'root' }) export class AuthService { public authenticated: boolean; public user?: User; constructor( private msalService: MsalService, private alertsService: AlertsService) { this.authenticated = false; this.user = undefined; } // Prompt the user to sign in and // grant consent to the requested permission scopes async signIn(): Promise<void> { const result = await this.msalService .loginPopup(OAuthSettings) .toPromise() .catch((reason) => { this.alertsService.addError('Login failed', JSON.stringify(reason, null, 2)); }); if (result) { this.msalService.instance.setActiveAccount(result.account); this.authenticated = true; // Temporary placeholder this.user = new User(); this.user.displayName = 'Adele Vance'; this.user.email = 'AdeleV@contoso.com'; this.user.avatar = '/assets/no-profile-photo.png'; // Temporary to display token in an error box this.alertsService.addSuccess('Token acquired', result.accessToken); } } // Sign out async signOut(): Promise<void> { await this.msalService.logout().toPromise(); this.user = undefined; this.authenticated = false; } }
Ouvrez ./src/app/nav-bar/nav-bar.component.ts et remplacez son contenu par ce qui suit.
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { User } from '../user'; @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 = false; // Is a user logged in? get authenticated(): boolean { return this.authService.authenticated; } // The user get user(): User | undefined { return this.authService.user; } constructor(private authService: AuthService) { } ngOnInit() { } // Used by the Bootstrap navbar-toggler button to hide/show // the nav in a collapsed state toggleNavBar(): void { this.showNav = !this.showNav; } async signIn(): Promise<void> { await this.authService.signIn(); } signOut(): void { this.authService.signOut(); } }
Ouvrez ./src/app/home/home.component.ts et remplacez son contenu par ce qui suit.
Enregistrez vos modifications et actualisez le navigateur. Cliquez sur le bouton Cliquer ici pour vous inscrire et vous devez être redirigé vers https://login.microsoftonline.com
. Connectez-vous avec votre compte Microsoft et consentez aux autorisations demandées. La page de l’application doit s’actualiser et afficher le jeton.
Obtenir les détails de l’utilisateur
Pour l’instant, le service d’authentification définit des valeurs constantes pour le nom d’affichage et l’adresse e-mail de l’utilisateur. Maintenant que vous avez un jeton d’accès, vous pouvez obtenir les détails utilisateur de Microsoft Graph afin que ces valeurs correspondent à l’utilisateur actuel.
Ouvrez ./src/app/auth.service.ts
import
et ajoutez les instructions suivantes en haut du fichier.import { Client } from '@microsoft/microsoft-graph-client'; import { AuthCodeMSALBrowserAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
Ajoutez une propriété à la
AuthService
classe appeléegraphClient
.public graphClient?: Client;
Ajoutez une nouvelle fonction à la classe
AuthService
appeléegetUser
.private async getUser(): Promise<User | undefined> { if (!this.authenticated) return undefined; const graphClient = Client.init({ // Initialize the Graph client with an auth // provider that requests the token from the // auth service authProvider: async(done) => { const token = await this.getAccessToken() .catch((reason) => { done(reason, null); }); if (token) { done(null, token); } else { done("Could not get an access token", null); } } }); // Get the user from Graph (GET /me) const graphUser: MicrosoftGraph.User = await graphClient .api('/me') .select('displayName,mail,mailboxSettings,userPrincipalName') .get(); const user = new User(); user.displayName = graphUser.displayName ?? ''; // Prefer the mail property, but fall back to userPrincipalName user.email = graphUser.mail ?? graphUser.userPrincipalName ?? ''; user.timeZone = graphUser.mailboxSettings?.timeZone ?? 'UTC'; // Use default avatar user.avatar = '/assets/no-profile-photo.png'; return user; }
Recherchez et supprimez le code suivant de la
signIn
méthode.// Temporary placeholder this.user = new User(); this.user.displayName = "Adele Vance"; this.user.email = "AdeleV@contoso.com"; this.user.avatar = '/assets/no-profile-photo.png'; // Temporary to display token in an error box this.alertsService.addSuccess('Token acquired', result);
À la place, ajoutez le code suivant.
this.user = await this.getUser();
Ce nouveau code utilise le SDK Microsoft Graph pour obtenir les détails de l’utilisateur,
User
puis crée un objet à l’aide des valeurs renvoyées par l’appel d’API.Modifiez
constructor
la classe pourAuthService
vérifier si l’utilisateur est déjà connecté et chargez ses détails si c’est le cas. Remplacez l’existantconstructor
par ce qui suit.constructor( private msalService: MsalService, private alertsService: AlertsService) { this.authenticated = this.msalService.instance .getAllAccounts().length > 0; this.getUser().then((user) => {this.user = user}); }
Maintenant, si vous enregistrez vos modifications et démarrez l’application, après vous être connectez, vous devez revenir sur la page d’accueil, mais l’interface utilisateur doit changer pour indiquer que vous êtes connecté.
Cliquez sur l’avatar de l’utilisateur dans le coin supérieur droit pour accéder au lien de connexion. Le fait de cliquer sur Se déconnecter réinitialise la session et vous ramène à la page d’accueil.
Stockage et actualisation des jetons
À ce stade, votre application dispose d’un jeton d’accès, qui est Authorization
envoyé dans l’en-tête des appels d’API. Il s’agit du jeton qui permet à l’application d’accéder au Graph Microsoft au nom de l’utilisateur.
Cependant, ce jeton est de courte durée. Le jeton expire une heure après son émission. Étant donné que l’application utilise la bibliothèque MSAL, vous n’avez pas besoin d’implémenter de logique de stockage ou d’actualisation de jeton. Le jeton MsalService
est mis en cache dans le stockage du navigateur. La acquireTokenSilent
méthode vérifie d’abord le jeton mis en cache et, s’il n’a pas expiré, elle le renvoie. Si elle a expiré, elle effectue une demande silencieuse pour en obtenir une nouvelle.
Obtenir l’affichage Calendrier
Dans cet exercice, vous allez incorporer le Graph Microsoft dans l’application. Pour cette application, vous allez utiliser la bibliothèque cliente microsoft-graph pour appeler Microsoft Graph.
Récupérer les événements de calendrier à partir d’Outlook
Ajoutez un nouveau service pour contenir tous vos Graph appels. Exécutez la commande suivante dans votre CLI.
ng generate service graph
Tout comme pour le service d’authentification que vous avez créé précédemment, la création d’un service vous permet de l’injecter dans tous les composants qui ont besoin d’accéder à Microsoft Graph.
Une fois la commande terminée, ouvrez ./src/app/graph.service.ts et remplacez son contenu par ce qui suit.
import { Injectable } from '@angular/core'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { AuthService } from './auth.service'; import { AlertsService } from './alerts.service'; @Injectable({ providedIn: 'root' }) export class GraphService { constructor( private authService: AuthService, private alertsService: AlertsService) {} async getCalendarView(start: string, end: string, timeZone: string): Promise<MicrosoftGraph.Event[] | undefined> { if (!this.authService.graphClient) { this.alertsService.addError('Graph client is not initialized.'); return undefined; } try { // GET /me/calendarview?startDateTime=''&endDateTime='' // &$select=subject,organizer,start,end // &$orderby=start/dateTime // &$top=50 const result = await this.authService.graphClient .api('/me/calendarview') .header('Prefer', `outlook.timezone="${timeZone}"`) .query({ startDateTime: start, endDateTime: end }) .select('subject,organizer,start,end') .orderby('start/dateTime') .top(50) .get(); return result.value; } catch (error) { this.alertsService.addError('Could not get events', JSON.stringify(error, null, 2)); } return undefined; } }
Que fait ce code ?
- Il initialise un client Graph client dans le constructeur du service.
- Il implémente une
getCalendarView
fonction qui utilise le client Graph de la manière suivante :- L’URL qui sera appelée est
/me/calendarview
. - La
header
méthode inclut l’en-têtePrefer: outlook.timezone
, qui place les heures de début et de fin des événements renvoyés dans le fuseau horaire préféré de l’utilisateur. - La
query
méthode ajoute les paramètresstartDateTime
endDateTime
et définit la fenêtre de temps pour l’affichage Calendrier. - La
select
méthode limite les champs renvoyés pour chaque événement à ceux que l’affichage utilisera réellement. - La
orderby
méthode trie les résultats par heure de début.
- L’URL qui sera appelée est
Créez un Angular pour appeler cette nouvelle méthode et afficher les résultats de l’appel. Exécutez la commande suivante dans votre CLI.
ng generate component calendar
Une fois la commande terminée,
routes
ajoutez le composant au tableau dans ./src/app/app-routing.module.ts.import { CalendarComponent } from './calendar/calendar.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'calendar', component: CalendarComponent }, ];
Ouvrez ./src/app/calendar/calendar.component.ts et remplacez son contenu par ce qui suit.
import { Component, OnInit } from '@angular/core'; import { parseISO } from 'date-fns'; import { endOfWeek, startOfWeek } from 'date-fns/esm'; import { zonedTimeToUtc } from 'date-fns-tz'; import { findIana } from 'windows-iana'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { AuthService } from '../auth.service'; import { GraphService } from '../graph.service'; import { AlertsService } from '../alerts.service'; @Component({ selector: 'app-calendar', templateUrl: './calendar.component.html', styleUrls: ['./calendar.component.css'] }) export class CalendarComponent implements OnInit { public events?: MicrosoftGraph.Event[]; constructor( private authService: AuthService, private graphService: GraphService, private alertsService: AlertsService) { } async ngOnInit() { // Convert the user's timezone to IANA format const ianaName = findIana(this.authService.user?.timeZone ?? 'UTC'); const timeZone = ianaName![0].valueOf() || this.authService.user?.timeZone || 'UTC'; // Get midnight on the start of the current week in the user's timezone, // but in UTC. For example, for Pacific Standard Time, the time value would be // 07:00:00Z const now = new Date(); const weekStart = zonedTimeToUtc(startOfWeek(now), timeZone); const weekEnd = zonedTimeToUtc(endOfWeek(now), timeZone); this.events = await this.graphService.getCalendarView( weekStart.toISOString(), weekEnd.toISOString(), this.authService.user?.timeZone ?? 'UTC'); // Temporary to display raw results this.alertsService.addSuccess('Events from Graph', JSON.stringify(events, null, 2)); } }
Pour l’instant, cela restituera simplement le tableau des événements dans JSON sur la page. Enregistrez vos modifications, puis redémarrez l’application. Connectez-vous et cliquez sur le lien Calendrier dans la barre de navigation. Si tout fonctionne, vous devriez voir une image mémoire JSON des événements dans le calendrier de l’utilisateur.
Afficher les résultats
Vous pouvez maintenant mettre à jour le CalendarComponent
composant pour afficher les événements de manière plus conviviale.
Supprimez le code temporaire qui ajoute une alerte à partir de la
ngOnInit
fonction. Votre fonction mise à jour doit ressembler à ceci.ngOnInit() { // Convert the user's timezone to IANA format const ianaName = findIana(this.authService.user?.timeZone ?? 'UTC'); const timeZone = ianaName![0].valueOf() || this.authService.user?.timeZone || 'UTC'; // Get midnight on the start of the current week in the user's timezone, // but in UTC. For example, for Pacific Standard Time, the time value would be // 07:00:00Z var startOfWeek = moment.tz(timeZone).startOf('week').utc(); var endOfWeek = moment(startOfWeek).add(7, 'day'); this.graphService.getCalendarView( startOfWeek.format(), endOfWeek.format(), this.authService.user?.timeZone ?? 'UTC') .then((events) => { this.events = events; }); }
Ajoutez une fonction à la classe
CalendarComponent
pour mettre en forme unDateTimeTimeZone
objet dans une chaîne ISO.formatDateTimeTimeZone(dateTime: MicrosoftGraph.DateTimeTimeZone | undefined | null): string { if (dateTime == undefined || dateTime == null) { return ''; } try { // Pass UTC for the time zone because the value // is already adjusted to the user's time zone return moment.tz(dateTime.dateTime, 'UTC').format(); } catch(error) { this.alertsService.addError('DateTimeTimeZone conversion error', JSON.stringify(error)); return ''; } }
Ouvrez ./src/app/calendar/calendar.component.html et remplacez son contenu par ce qui suit.
<h1>Calendar</h1> <a class="btn btn-light btn-sm mb-3" routerLink="/newevent">New event</a> <table class="table"> <thead> <th scope="col">Organizer</th> <th scope="col">Subject</th> <th scope="col">Start</th> <th scope="col">End</th> </thead> <tbody> <tr *ngFor="let event of events"> <td>{{event.organizer?.emailAddress?.name}}</td> <td>{{event.subject}}</td> <!-- Use 'UTC' in the pipe to date so Angular will not convert the already converted time to local time. See https://angular.io/api/common/DatePipe --> <td>{{formatDateTimeTimeZone(event.start) | date:'short' : 'UTC' }}</td> <td>{{formatDateTimeTimeZone(event.end) | date: 'short' : 'UTC' }}</td> </tr> </tbody> </table>
Cette opération pare la collection d’événements et ajoute une ligne de tableau pour chacun d’eux. Enregistrez les modifications et redémarrez l’application. Cliquez sur le lien Calendrier et l’application doit maintenant restituer une table des événements.
Créer un événement
Dans cette section, vous allez ajouter la possibilité de créer des événements sur le calendrier de l’utilisateur.
Ouvrez ./src/app/graph.service.ts et ajoutez la fonction suivante à la
GraphService
classe.async addEventToCalendar(newEvent: MicrosoftGraph.Event): Promise<void> { try { // POST /me/events await this.graphClient .api('/me/events') .post(newEvent); } catch (error) { throw Error(JSON.stringify(error, null, 2)); } }
Créer un formulaire d’événement
Créez un Angular pour afficher un formulaire et appeler cette nouvelle fonction. Exécutez la commande suivante dans votre CLI.
ng generate component new-event
Une fois la commande terminée,
routes
ajoutez le composant au tableau dans ./src/app/app-routing.module.ts.import { NewEventComponent } from './new-event/new-event.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'calendar', component: CalendarComponent }, { path: 'newevent', component: NewEventComponent }, ];
Créez un fichier dans le répertoire ./src/app/new-event nommé new-event.ts et ajoutez le code suivant.
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; // Model for the new event form export class NewEvent { subject?: string; attendees?: string; start?: string; end?: string; body?: string; // Generate a MicrosoftGraph.Event from the model getGraphEvent(timeZone: string): MicrosoftGraph.Event { const graphEvent: MicrosoftGraph.Event = { subject: this.subject, start: { dateTime: this.start, timeZone: timeZone }, end: { dateTime: this.end, timeZone: timeZone } }; // If there are attendees, convert to array // and add them if (this.attendees && this.attendees.length > 0) { graphEvent.attendees = []; const emails = this.attendees.split(';'); emails.forEach(email => { graphEvent.attendees?.push({ type: 'required', emailAddress: { address: email } }); }); } // If there is a body, add it as plain text if (this.body && this.body.length > 0) { graphEvent.body = { contentType: 'text', content: this.body }; } return graphEvent; } }
Cette classe servira de modèle pour le nouveau formulaire d’événement.
Ouvrez ./src/app/new-event/new-event.component.ts et remplacez son contenu par le code suivant.
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { GraphService } from '../graph.service'; import { AlertsService } from '../alerts.service'; import { NewEvent } from './new-event'; @Component({ selector: 'app-new-event', templateUrl: './new-event.component.html', styleUrls: ['./new-event.component.css'] }) export class NewEventComponent implements OnInit { model = new NewEvent(); constructor( private authService: AuthService, private graphService: GraphService, private alertsService: AlertsService) { } ngOnInit(): void { } onSubmit(): void { const timeZone = this.authService.user?.timeZone ?? 'UTC'; const graphEvent = this.model.getGraphEvent(timeZone); this.graphService.addEventToCalendar(graphEvent) .then(() => { this.alertsService.addSuccess('Event created.'); }).catch(error => { this.alertsService.addError('Error creating event.', error.message); }); } }
Ouvrez ./src/app/new-event/new-event.component.html et remplacez son contenu par le code suivant.
<h1>New event</h1> <form (ngSubmit)="onSubmit()" #newEventForm="ngForm"> <div class="form-group"> <label for="subject">Subject</label> <input type="text" class="form-control" id="subject" required [(ngModel)]="model.subject" name="subject" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">Subject is required</div> </div> <div class="form-group"> <label for="attendees">Attendees</label> <input type="text" class="form-control" id="attendees" placeholder="Enter one or more email addresses (separated with a ;) to add attendees" [(ngModel)]="model.attendees" name="attendees" #name="ngModel"> </div> <div class="form-row"> <div class="col"> <div class="form-group"> <label for="start">Start</label> <input type="datetime-local" class="form-control" id="start" required [(ngModel)]="model.start" name="start" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">Start is required</div> </div> </div> <div class="col"> <div class="form-group"> <label for="end">End</label> <input type="datetime-local" class="form-control" id="end" required [(ngModel)]="model.end" name="end" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">End is required</div> </div> </div> </div> <div class="form-group"> <label for="body">Body</label> <textarea class="form-control" id="body" rows="4" [(ngModel)]="model.body" name="body" #name="ngModel"></textarea> </div> <button type="submit" class="btn btn-primary mr-2" [disabled]="!newEventForm.form.valid">Create</button> <a class="btn btn-secondary" routerLink="/calendar">Cancel</a> </form>
Enregistrez les modifications et actualisez l’application. Sélectionnez le bouton Nouvel événement dans la page Calendrier, puis utilisez le formulaire pour créer un événement sur le calendrier de l’utilisateur.
Félicitations !
Vous avez terminé le didacticiel Angular Microsoft Graph. Maintenant que vous disposez d’une application de travail qui appelle Microsoft Graph, vous pouvez expérimenter et ajouter de nouvelles fonctionnalités. Consultez la vue d’ensemble de Microsoft Graph pour voir toutes les données accessibles avec Microsoft Graph.
Commentaires
N’hésitez pas à nous faire part de vos commentaires sur ce didacticiel dans GitHub référentiel.
Vous avez un problème avec cette section ? Si c'est le cas, faites-nous part de vos commentaires pour que nous puissions l'améliorer.