Articles

Construire une application CRUD de base avec Angular et Node

Posted on

Ces dernières années, les applications à page unique (SPA) sont devenues de plus en plus populaires. Une SPA est un site web qui se compose d’une seule page. Cette page unique agit comme un conteneur pour une application JavaScript. Le JavaScript est chargé d’obtenir le contenu et de le rendre dans le conteneur. Le contenu est généralement obtenu à partir d’un service Web et les API RESTful sont devenues le meilleur choix dans de nombreuses situations. La partie de l’application qui constitue le SPA est communément appelée client ou front-end, tandis que la partie responsable de l’API REST est appelée serveur ou back-end. Dans ce tutoriel, vous allez développer une simple application monopage Angular avec un back-end REST, basée sur Node et Express.

Vous utiliserez Angular car il suit le modèle MVC et sépare proprement la vue des modèles. Il est simple de créer des modèles HTML qui sont dynamiquement remplis de données et automatiquement mis à jour lorsque les données changent. J’en suis venu à aimer ce framework car il est très puissant, possède une énorme communauté et une excellente documentation.

Pour le serveur, vous utiliserez Node avec Express. Express est un framework qui facilite la création d’API REST en permettant de définir le code qui s’exécute pour différentes requêtes sur le serveur. Des services supplémentaires peuvent être ajoutés de manière globale ou en fonction de la demande. Il existe un certain nombre de frameworks qui s’appuient sur Express et automatisent la transformation de vos modèles de base de données en API. Ce tutoriel ne fera usage d’aucun d’entre eux afin de rester concentré.

Angular encourage l’utilisation de TypeScript. TypeScript ajoute des informations de typage à JavaScript et, à mon avis, est l’avenir du développement d’applications à grande échelle en JavaScript. Pour cette raison, vous allez développer à la fois le client et le serveur en utilisant TypeScript.

Voici les bibliothèques que vous utiliserez pour le client et le serveur :

  • Angular : Le framework utilisé pour construire l’application client
  • Okta for Authorisation : Un plugin qui gère l’autorisation d’authentification unique en utilisant Okta, à la fois sur le client et le serveur
  • Angular Material : Un plugin angulaire qui fournit un Material Design prêt à l’emploi
  • Node : Le serveur réel qui exécute le code JavaScript
  • Express : Une bibliothèque de routage pour répondre aux demandes du serveur et construire des API REST
  • TypeORM : Une bibliothèque ORM de base de données pour TypeScript

Démarrez votre application client Angular de base

Démarrons en mettant en œuvre un client de base à l’aide d’Angular. L’objectif est de développer un catalogue de produits qui vous permet de gérer les produits, leurs prix et leurs niveaux de stock. À la fin de cette section, vous disposerez d’une application simple composée d’une barre supérieure et de deux vues, Accueil et Produits. La vue Produits n’aura pas encore de contenu et rien ne sera protégé par un mot de passe. Cela sera couvert dans les sections suivantes.

Pour commencer, vous devrez installer Angular. Je vais supposer que vous avez déjà Node installé sur votre système et que vous pouvez utiliser la commande npm. Tapez la commande suivante dans un terminal.

npm install -g @angular/[email protected]

Selon votre système, vous devrez peut-être exécuter cette commande en utilisant sudo car elle installera le paquet globalement. Le paquet angular-cli fournit la commande ng qui est utilisée pour gérer les applications Angular. Une fois installé, allez dans un répertoire de votre choix et créez votre première application Angular à l’aide de la commande suivante.

ng new MyAngularClient

En utilisant Angular 7, cela vous demandera deux requêtes. La première vous demande si vous voulez inclure le routage. Répondez par l’affirmative à cette question. La deuxième requête concerne le type de feuilles de style que vous voulez utiliser. Laissez cela au CSS par défaut.

ng new va créer un nouveau répertoire appelé MyAngularClient et le peupler d’un squelette d’application. Prenons un peu de temps pour examiner certains des fichiers créés par la commande précédente. Dans le répertoire src de l’application, vous trouverez un fichier index.html qui est la page principale de l’application. Il ne contient pas grand-chose et joue simplement le rôle de conteneur. Vous verrez également un fichier style.css. Il contient la feuille de style globale qui est appliquée à l’ensemble de l’application. Si vous parcourez les dossiers, vous pourriez remarquer un répertoire src/app contenant cinq fichiers.

app-routing.module.tsapp.component.cssapp.component.htmlapp.component.tsapp.component.spec.tsapp.module.ts

Ces fichiers définissent le composant principal de l’application qui sera inséré dans le index.html. Voici une brève description de chacun de ces fichiers :

  • Le fichier app.component.css contient les feuilles de style du composant principal app. Les styles peuvent être définis localement pour chaque composant
  • app.component.html contient le modèle HTML du composant
  • app.component.ts fichier contient le code contrôlant la vue
  • app.module.ts définit quels modules votre app utilisera
  • app-routing.module.ts est mis en place pour définir les routes de votre application
  • app.component.spec.ts contient un squelette pour le test unitaire du app composant

Je ne couvrirai pas les tests dans ce tutoriel, mais dans les applications de la vie réelle, vous devriez faire usage de cette fonctionnalité. Avant de pouvoir commencer, vous devrez installer quelques paquets supplémentaires. Ceux-ci vous aideront à créer rapidement une mise en page réactive bien conçue. Naviguez dans le répertoire de base du client, MyAngularClient, et tapez la commande suivante.

Les bibliothèques @angular/material et @angular/cdk fournissent des composants basés sur le Material Design de Google, @angular/animations est utilisée pour fournir des transitions fluides, et @angular/flex-layout vous donne les outils pour rendre votre design responsive.

Puis, créez le modèle HTML pour le composant app. Ouvrez src/app/app.component.html et remplacez le contenu par ce qui suit .

<mat-toolbar color="primary" class="expanded-toolbar"> <button mat-button routerLink="/">{{title}}</button> <div fxLayout="row" fxShow="false" fxShow.gt-sm> <button mat-button routerLink="/"><mat-icon>home</mat-icon></button> <button mat-button routerLink="/products">Products</button> <button mat-button *ngIf="!isAuthenticated" (click)="login()"> Login </button> <button mat-button *ngIf="isAuthenticated" (click)="logout()"> Logout </button> </div> <button mat-button ="menu" fxHide="false" fxHide.gt-sm> <mat-icon>menu</mat-icon> </button></mat-toolbar><mat-menu x-position="before" #menu="matMenu"> <button mat-menu-item routerLink="/"><mat-icon>home</mat-icon> Home</button> <button mat-menu-item routerLink="/products">Products</button>; <button mat-menu-item *ngIf="!isAuthenticated" (click)="login()"> Login </button> <button mat-menu-item *ngIf="isAuthenticated" (click)="logout()"> Logout </button></mat-menu><router-outlet></router-outlet>

Le mat-toolbar contient la barre d’outils de conception matérielle, tandis que router-outlet est le conteneur qui sera rempli par le routeur. Le fichier app.component.ts doit être modifié pour contenir ce qui suit.

import { Component } from '@angular/core';@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: })export class AppComponent { public title = 'My Angular App'; public isAuthenticated: boolean; constructor() { this.isAuthenticated = false; } login() { } logout() { }}

C’est le contrôleur du composant app. Vous pouvez voir qu’il contient une propriété appelée isAuthenticated ainsi que deux méthodes login et logout. Pour l’instant, ces méthodes ne font rien. Ils seront mis en œuvre dans la prochaine section qui couvre l’authentification des utilisateurs avec Okta. Définissez maintenant tous les modules que vous allez utiliser. Remplacez le contenu de app.module.ts par le code ci-dessous :

import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { BrowserAnimationsModule } from '@angular/platform-browser/animations';import { FlexLayoutModule } from '@angular/flex-layout';import { MatButtonModule, MatDividerModule, MatIconModule, MatMenuModule, MatProgressSpinnerModule, MatTableModule, MatToolbarModule} from '@angular/material';import { HttpClientModule } from '@angular/common/http';import { FormsModule } from '@angular/forms';import { AppRoutingModule } from './app-routing.module';import { AppComponent } from './app.component';@NgModule({ declarations: , imports: , providers: , bootstrap: })export class AppModule { }

Notez tous les modules de conception matérielle. La bibliothèque @angular/material vous demande d’importer un module pour chaque type de composant que vous souhaitez utiliser dans votre application. À partir d’Angular 7, le squelette d’application par défaut contient un fichier distinct appelé app-routing.module.ts. Modifiez-le pour déclarer les routes suivantes.

import { NgModule } from '@angular/core';import { Routes, RouterModule } from '@angular/router';import { ProductsComponent } from './products/products.component';import { HomeComponent } from './home/home.component';const routes: Routes = ;@NgModule({ imports: , exports: })export class AppRoutingModule { }

Ce fichier définit deux routes correspondant au chemin de la racine et au chemin products. Elle attache également le HomeComponent et le ProductsComponent à ces routes. Créez ces composants maintenant. Dans le répertoire de base du client Angular, tapez les commandes suivantes .

ng generate component Productsng generate component Home

Ceci crée htmlcssts, et spec.ts fichiers pour chaque composant. Il met également à jour app.module.ts pour déclarer les nouveaux composants. Ouvrez home.component.html dans le répertoire src/app/home et collez le contenu suivant .

<div class="hero"> <div> <h1>Hello World</h1> <p class="lead">This is the homepage of your Angular app</p> </div></div>

Incluez également du style dans le fichier home.component.css.

.hero { text-align: center; height: 90vh; display: flex; flex-direction: column; justify-content: center; font-family: sans-serif;}

Laissez le ProductsComponent vide pour le moment. Cela sera mis en œuvre une fois que vous aurez créé le serveur REST back-end et que vous serez en mesure de le remplir avec quelques données. Pour que tout soit beau, il ne reste que deux petites tâches. Copiez les styles suivants dans src/style.css

@import "~@angular/material/prebuilt-themes/deeppurple-amber.css";body { margin: 0; font-family: sans-serif;}.expanded-toolbar { justify-content: space-between;}h1 { text-align: center;}

Enfin, afin de rendre les icônes Material Design, ajoutez une ligne à l’intérieur des balises <head> du fichier index.html.

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

Vous êtes maintenant prêt à allumer le serveur Angular et à voir ce que vous avez réalisé jusqu’à présent. Dans le répertoire de base de l’application cliente, tapez la commande suivante.

ng serve

Puis ouvrez votre navigateur et naviguez vers http://localhost:4200.

Ajouter l’authentification à votre application Node + Angular

Si vous avez déjà développé des applications web à partir de zéro, vous savez combien de travail est nécessaire juste pour permettre aux utilisateurs de s’inscrire, de vérifier, de se connecter et de se déconnecter de votre application. En utilisant Okta, ce processus peut être grandement simplifié. Pour commencer, vous aurez besoin d’un compte de développeur avec Okta.

developer.okta.com

Dans votre navigateur, naviguez sur developer.okta.com et cliquez sur Créer un compte gratuit et entrez vos coordonnées.

Démarrez la construction sur Okta

Une fois que vous avez terminé, vous serez amené à votre tableau de bord de développeur. Cliquez sur le bouton Add Application pour créer une nouvelle application.

Add Application

Démarrez en créant une nouvelle application à page unique. Choisissez Single Page App et cliquez sur Next.

Create new Single Page App

Sur la page suivante, vous devrez modifier les paramètres par défaut. Assurez-vous que le numéro de port est bien 4200. C’est le port par défaut pour les applications Angular.

My Angular App

C’est tout. Vous devriez maintenant voir un ID client que vous devrez coller dans votre code TypeScript.

Pour implémenter l’authentification dans le client, installez la bibliothèque Okta pour Angular.

npm install @okta/[email protected] --save-exact

Dans app.module.ts importez la OktaAuthModule.

import { OktaAuthModule } from '@okta/okta-angular';

Dans la liste des imports du module app, ajouter :

OktaAuthModule.initAuth({ issuer: 'https://{yourOktaDomain}/oauth2/default', redirectUri: 'http://localhost:4200/implicit/callback', clientId: '{YourClientId}'})

Ici yourOktaDomain doit être remplacé par le domaine de développement que vous voyez dans votre navigateur lorsque vous naviguez sur votre tableau de bord Okta. YourClientId doit être remplacé par l’ID client que vous avez obtenu lors de l’enregistrement de votre application. Le code ci-dessus rend le module d’authentification Okta disponible dans votre application. Utilisez-le dans app.component.ts, et importez le service.

import { OktaAuthService } from '@okta/okta-angular';

Modifiez le constructeur pour injecter le service et vous y abonner.

constructor(public oktaAuth: OktaAuthService) { this.oktaAuth.$authenticationState.subscribe( (isAuthenticated: boolean) => this.isAuthenticated = isAuthenticated );}

Maintenant, tout changement dans le statut d’authentification sera reflété dans la propriété isAuthenticated. Vous devrez tout de même l’initialiser lors du chargement du composant. Créez une méthode ngOnInit et ajoutez implements OnInit à votre définition de classe

import { Component, OnInit } from '@angular/core';...export class AppComponent implements OnInit { ... async ngOnInit() { this.isAuthenticated = await this.oktaAuth.isAuthenticated(); }}

Enfin, implémentez la méthode login et logout pour réagir à l’interface utilisateur et connecter l’utilisateur en entrée ou en sortie.

login() { this.oktaAuth.loginRedirect();}logout() { this.oktaAuth.logout('/');}

Dans le module de routage, vous devez enregistrer la route qui sera utilisée pour la demande de connexion. Ouvrez app-routing.module.ts et importez OktaCallbackComponent et OktaAuthGuard.

import { OktaCallbackComponent, OktaAuthGuard } from '@okta/okta-angular';

Ajouter une autre route au tableau routes.

{ path: 'implicit/callback', component: OktaCallbackComponent}

Ceci permettra à l’utilisateur de se connecter en utilisant le bouton Login. Pour protéger la route Products des accès non autorisés, ajoutez la ligne suivante à la route products.

{ path: 'products', component: ProductsComponent, canActivate: }

C’est tout ce qu’il y a à faire. Maintenant, lorsqu’un utilisateur essaie d’accéder à la vue Produits, il sera redirigé vers la page de connexion Okta. Une fois connecté, l’utilisateur sera redirigé vers la vue Produits.

Implémenter une API REST Node

L’étape suivante consiste à implémenter un serveur basé sur Node et Express qui stockera les informations sur les produits. Cela utilisera un certain nombre de petites bibliothèques pour vous faciliter la vie. Pour développer en TypeScript, vous aurez besoin de typescript et tsc. Pour la couche d’abstraction de la base de données, vous utiliserez TypeORM. Il s’agit d’une bibliothèque pratique qui injecte un comportement dans les classes TypeScript et les transforme en modèles de base de données. Créez un nouveau répertoire pour contenir votre application serveur, puis exécutez la commande suivante dans celui-ci.

npm init

Répondre à toutes les questions, puis exécuter :

Je ne vais pas couvrir toutes ces bibliothèques en détail, mais vous verrez que @okta/jwt-verifier est utilisé pour vérifier les jetons Web JSON et les authentifier.

Afin de faire fonctionner TypeScript, créez un fichier tsconfig.json et collez-y le contenu suivant.

{ "compilerOptions": { "target": "es6", "module": "commonjs", "outDir": "dist", "experimentalDecorators": true, "emitDecoratorMetadata": true }, "include": , "exclude": }

La première étape de la création du serveur consiste à créer un modèle de base de données pour le produit. En utilisant TypeORM, ceci est simple. Créez un sous-répertoire src et à l’intérieur de celui-ci créez un fichier model.ts. Collez le contenu suivant.

import {Entity, PrimaryGeneratedColumn, Column, createConnection, Connection, Repository} from 'typeorm';@Entity()export class Product { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() sku: string; @Column('text') description: string; @Column() price: number; @Column() stock: number;}

Les annotations TypeORM transforment la définition de la classe en un modèle de base de données. J’adore le projet TypeORM en raison de sa facilité d’utilisation et de la grande variété de connecteurs de bases de données SQL et NoSQL qui sont pris en charge. Je vous suggère de consulter la documentation à l’adresse https://github.com/typeorm/typeorm.

Vous devrez également obtenir l’accès à un référentiel de produits. Aussi, dans le fichier model.ts ajoutez ce qui suit.

let connection:Connection;export async function getProductRepository(): Promise<Repository<Product>> { if (connection===undefined) { connection = await createConnection({ type: 'sqlite', database: 'myangularapp', synchronize: true, entities: , }); } return connection.getRepository(Product);}

Notez que ceci utilise SQLite pour la simplicité ici. Dans un scénario réel, vous devriez remplacer cela par un connecteur de base de données de votre choix.

Puis, créez un fichier appelé product.ts. Ce fichier contiendra la logique de toutes les routes pour les opérations CRUD sur les produits.

import { NextFunction, Request, Response, Router } from 'express';import { getProductRepository, Product } from './model';export const router: Router = Router();router.get('/product', async function (req: Request, res: Response, next: NextFunction) { try { const repository = await getProductRepository(); const allProducts = await repository.find(); res.send(allProducts); } catch (err) { return next(err); }});router.get('/product/:id', async function (req: Request, res: Response, next: NextFunction) { try { const repository = await getProductRepository(); const product = await repository.find({id: req.params.id}); res.send(product); } catch (err) { return next(err); }});router.post('/product', async function (req: Request, res: Response, next: NextFunction) { try { const repository = await getProductRepository(); const product = new Product(); product.name = req.body.name; product.sku = req.body.sku; product.description = req.body.description; product.price = Number.parseFloat(req.body.price); product.stock = Number.parseInt(req.body.stock); const result = await repository.save(product); res.send(result); } catch (err) { return next(err); }});router.post('/product/:id', async function (req: Request, res: Response, next: NextFunction) { try { const repository = await getProductRepository(); const product = await repository.findOne({id: req.params.id}); product.name = req.body.name; product.sku = req.body.sku; product.description = req.body.description; product.price = Number.parseFloat(req.body.price); product.stock = Number.parseInt(req.body.stock); const result = await repository.save(product); res.send(result); } catch (err) { return next(err); }});router.delete('/product/:id', async function (req: Request, res: Response, next: NextFunction) { try { const repository = await getProductRepository(); await repository.delete({id: req.params.id}); res.send('OK'); } catch (err) { return next(err); }});

Ce fichier est un peu long mais ne contient rien de surprenant. Product les objets sont créés et enregistrés dans ou supprimés de la base de données.

Tournons à nouveau notre attention vers l’authentification. Vous voudrez vous assurer que seuls les utilisateurs authentifiés peuvent accéder au service. Créez un fichier appelé auth.ts et collez ce qui suit .

import { Request, Response, NextFunction} from 'express';const OktaJwtVerifier = require('@okta/jwt-verifier');const oktaJwtVerifier = new OktaJwtVerifier({ clientId: '{YourClientId}', issuer: 'https://{yourOktaDomain}/oauth2/default'});export async function oktaAuth(req:Request, res:Response, next:NextFunction) { try { const token = (req as any).token; if (!token) { return res.status(401).send('Not Authorised'); } const jwt = await oktaJwtVerifier.verifyAccessToken(token); req.user = { uid: jwt.claims.uid, email: jwt.claims.sub }; next(); } catch (err) { return res.status(401).send(err.message); }}

Comme dans l’application client yourOktaDomain doit être remplacé par le domaine de développement et YourClientId doit être remplacé par l’ID client de votre application. L’instance oktaJwtVerifier prend un jeton JWT et l’authentifie. En cas de succès, l’identifiant et l’email de l’utilisateur seront stockés dans req.user. Dans le cas contraire, le serveur répondra avec un code d’état 401. La dernière pièce pour compléter le serveur est le point d’entrée principal qui démarre réellement le serveur et enregistre le middleware que vous avez défini jusqu’à présent. Créez un fichier server.ts avec le contenu suivant .

import * as express from 'express';import * as cors from 'cors';import * as bodyParser from 'body-parser';const bearerToken = require('express-bearer-token');import {router as productRouter} from './product'import {oktaAuth} from './auth'const app = express() .use(cors()) .use(bodyParser.json()) .use(bearerToken()) .use(oktaAuth) .use(productRouter);app.listen(4201, (err) => { if (err) { return console.log(err); } return console.log('My Node App listening on port 4201');});

Pour compiler le TypeScript, exécutez la commande

npx tsc

Puis, si vous voulez démarrer le serveur, exécutez simplement :

node dist/server.js

Finissez votre client Angular

Maintenant que le serveur est terminé, terminons le client. La première étape consiste à créer une classe qui contient les données du produit. Cette classe est similaire à la classe Product de l’application serveur mais sans les annotations TypeORM. Elle sera contenue dans un fichier appelé product.ts.

export class Product { id?: string; name: string; sku: string; description: string; price: number; stock: number;}

Enregistrez ce fichier dans le même répertoire que le composant products. Il est préférable d’encapsuler l’accès à l’API REST dans un service distinct. Créez un service Products en exécutant la commande ci-dessous.

ng generate service products/Products

Cela va créer un fichier appelé product.service.ts dans le répertoire src/app/products. Remplissez-le avec le contenu suivant.

import { Injectable } from '@angular/core';import { HttpClient } from '@angular/common/http';import { OktaAuthService } from '@okta/okta-angular';import { Product } from './product';const baseUrl = 'http://localhost:4201';@Injectable({ providedIn: 'root'})export class ProductsService { constructor(public oktaAuth: OktaAuthService, private http: HttpClient) { } private async request(method: string, url: string, data?: any) { const token = await this.oktaAuth.getAccessToken(); console.log('request ' + JSON.stringify(data)); const result = this.http.request(method, url, { body: data, responseType: 'json', observe: 'body', headers: { Authorization: `Bearer ${token}` } }); return new Promise<any>((resolve, reject) => { result.subscribe(resolve as any, reject as any); }); } getProducts() { return this.request('get', `${baseUrl}/product`); } getProduct(id: string) { return this.request('get', `${baseUrl}/product/${id}`); } createProduct(product: Product) { console.log('createProduct ' + JSON.stringify(product)); return this.request('post', `${baseUrl}/product`, product); } updateProduct(product: Product) { console.log('updateProduct ' + JSON.stringify(product)); return this.request('post', `${baseUrl}/product/${product.id}`, product); } deleteProduct(id: string) { return this.request('delete', `${baseUrl}/product/${id}`); }}

Le ProductsService contient une méthode publique pour chaque route de l’API REST. La requête HTTP est encapsulée dans une méthode distincte. Notez comment la requête contient toujours un Bearer jeton obtenu à partir du OktaAuthService. C’est le jeton utilisé par le serveur pour authentifier l’utilisateur.

Maintenant, le ProductsComponent peut être mis en œuvre. Le code suivant fera l’affaire.

import { Component, OnInit } from '@angular/core';import { MatTableDataSource } from '@angular/material';import { ProductsService } from './products.service';import { Product } from './product';@Component({ selector: 'app-products', templateUrl: './products.component.html', styleUrls: })export class ProductsComponent implements OnInit { displayedColumns: string = ; dataSource = new MatTableDataSource<any>(); selectedProduct: Product = new Product(); loading = false; constructor(public productService: ProductsService) { } ngOnInit() { this.refresh(); } async refresh() { this.loading = true; const data = await this.productService.getProducts(); this.dataSource.data = data; this.loading = false; } async updateProduct() { if (this.selectedProduct.id !== undefined) { await this.productService.updateProduct(this.selectedProduct); } else { await this.productService.createProduct(this.selectedProduct); } this.selectedProduct = new Product(); await this.refresh(); } editProduct(product: Product) { this.selectedProduct = product; } clearProduct() { this.selectedProduct = new Product(); } async deleteProduct(product: Product) { this.loading = true; if (confirm(`Are you sure you want to delete the product ${product.name}. This cannot be undone.`)) { this.productService.deleteProduct(product.id); } await this.refresh(); }}

La mise en page, dans products.component.html, montrant le produit se compose de deux parties. La première partie utilise un composant mat-table pour afficher une liste de produits. La deuxième partie affiche un formulaire dans lequel l’utilisateur peut modifier un produit nouveau ou existant.

<h1 class="h1">Product Inventory</h1><div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between stretch" class="products"> <table mat-table fxFlex="100%" fxFlex.gt-sm="66%" ="dataSource" class="mat-elevation-z1"> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef> Name</th> <td mat-cell *matCellDef="let product"> {{product.name}}</td> </ng-container> <ng-container matColumnDef="sku"> <th mat-header-cell *matHeaderCellDef> SKU</th> <td mat-cell *matCellDef="let product"> {{product.sku}}</td> </ng-container> <ng-container matColumnDef="description"> <th mat-header-cell *matHeaderCellDef> Description</th> <td mat-cell *matCellDef="let product"> {{product.description}}</td> </ng-container> <ng-container matColumnDef="price"> <th mat-header-cell *matHeaderCellDef> Price</th> <td mat-cell *matCellDef="let product"> {{product.price}}</td> </ng-container> <ng-container matColumnDef="stock"> <th mat-header-cell *matHeaderCellDef> Stock Level</th> <td mat-cell *matCellDef="let product"> {{product.stock}}</td> </ng-container> <ng-container matColumnDef="edit"> <th mat-header-cell *matHeaderCellDef></th> <td mat-cell *matCellDef="let product"> <button mat-icon-button (click)="editProduct(product)"> <mat-icon>edit</mat-icon> </button> </td> </ng-container> <ng-container matColumnDef="delete"> <th mat-header-cell *matHeaderCellDef></th> <td mat-cell *matCellDef="let product"> <button mat-icon-button (click)="deleteProduct(product)"> <mat-icon>delete</mat-icon> </button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-divider fxShow="false" fxShow.gt-sm ="true"></mat-divider> <div> <h2>Selected Product</h2> <label>Name <input type="text" ="selectedProduct.name"> </label> <label>SKU <input type="text" ="selectedProduct.sku"> </label> <label>Description <input type="text" ="selectedProduct.description"> </label> <label>Price <input type="text" ="selectedProduct.price"> </label> <label>Stock Level <input type="text" ="selectedProduct.stock"> </label> <button mat-flat-button color="primary" (click)="updateProduct()">{{(selectedProduct.id!==undefined)?'Update':'Create'}}</button> <button mat-flat-button color="primary" (click)="clearProduct()">Clear</button> </div> <div class="loading" *ngIf="loading"> <mat-spinner></mat-spinner> </div></div>

Enfin, ajoutez un peu de style dans products.component.css à la mise en page.

.products { padding: 2rem;}label, input { display: block;}label { margin-bottom: 1rem;}.loading { position: absolute; display: flex; justify-content: center; align-content: center; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.8);}

Quand tout est terminé, vous pouvez démarrer le client et le serveur et tester votre application. Pour répéter, dans le répertoire contenant le serveur, exécutez :

node dist/server.js

Et dans le répertoire du client, exécutez :

ng serve

Votre application devrait ressembler quelque peu à ce qui suit

Product Inventory

En savoir plus sur Angular, Node, et Express

Dans ce tutoriel, je vous ai guidé à travers le développement d’une application web à page unique en utilisant Angular et Node. En utilisant seulement quelques lignes de code, vous avez pu mettre en œuvre l’authentification des utilisateurs pour le client et le serveur. Angular utilise TypeScript qui est un surensemble du langage JavaScript et ajoute des informations de type. TypeScript permet d’obtenir un code plus stable et c’est pourquoi j’ai décidé d’implémenter également le serveur Node/Express en utilisant ce langage. Si vous n’êtes pas encore familiarisé avec TypeScript, consultez cette excellente introduction de Todd Motto. Il a également quelques bons articles sur Angular.

Le code complet de ce tutoriel peut être trouvé sur GitHub.

Si vous êtes prêt à en apprendre davantage sur Angular, ou Node/Express, nous avons d’autres ressources à vous proposer :

  • Simple authentification Node
  • Construire une application CRUD de base avec Node et React
  • Construire un service API simple avec Express et GraphQL
  • Angular 6 – Quoi de neuf et pourquoi mettre à niveau ?
  • Construire une application CRUD de base avec Angular 7 et Spring Boot

Et comme toujours, nous serions ravis que vous nous suiviez pour plus de contenu cool et de mises à jour de notre équipe. Vous pouvez nous trouver sur Twitter @oktadev, sur Facebook et sur LinkedIn.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *