English English

Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/ard-site/templates/ardsite/library/Designer/Content/SingleArticle.php on line 198

MEAN Stack - Introduction à la création d'une application MEAN Stack avec Angular 9

Ce tutoriel vous montrera comment créer une application "MEAN stack" (pile d'applications) avec une rétrocompatibilité pour les anciens navigateurs.
Nous allons créer une application web qui effectue des opérations "CRUD" (pour : create, replace, update and delete).

Une application de la pile "MEAN" a un "backend" qui utilise "NodeJS" et un "frontend" qui utilise "Angular". "Express" est un serveur qui permet l'accès au "backend" depuis l'extérieur (le "frontend"). "MongoDB" est utilisé comme base de données, c'est-à-dire une base de données NoSQL qui enregistre les données dans des fichiers texte (format "JSON").
Le langage de programmation "JavaScript" est utilisé avec le framework "NodeJS" dans le "backend". Le "frontend" utilise également "TypeScript" qui est similaire à "JavaScript" et qui supporte tous les types de données.
Le "TypeScript" a également plus de fonctionnalités. Plus d'informations sur "TypeScript" :
https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html

 

Exigences

Vous devez installer MongoDB:
https://www.mongodb.com/download-center/community

MongoDB doit être déjà configuré. MongoDB fonctionne sur localhost sur la même machine dans ce tutoriel.

Vous devez installer NodeJS :
https://nodejs.org/en/download/

Vous devez installer le CLI angulaire :

npm install -g @angular/cli

Nous pouvons maintenant commencer à créer notre application. D'autres dépendances seront installées plus tard.
Veuillez créer un dossier de projet pour notre application "MEAN" stack. Nous appellerons cette application "mean_crud_example".

 

NodeJS - Backend

Nous commencerons par le "backend" de notre demande. Vous devez configurer le "backend" avec le gestionnaire de paquets "npm" de votre installation "NodeJS".

Créez un dossier appelé "backend".

 

mkdir backend


Exécutez cette commande dans ce dossier:

npm init

Il vous sera demandé la configuration de votre application "NodeJS". Mais vous pouvez utiliser les paramètres par défaut. Le code de notre application "NodeJS" est enregistré principalement dans le fichier "server.js", que nous créerons plus tard.

 

Nous utiliserons "Babel" pour assurer la rétrocompatibilité de notre "app". Grâce à "Babel", nous pouvons également utiliser le code "Javascript ES6" dans notre application "NodeJS".
Veuillez installer les paquets suivants :

npm install --save-dev @babel/core @babel/cli @babel/preset-env babel-watch
npm install --save @babel/polyfill


"Babel" a besoin du fichier de configuration ".babelrc", qui doit se trouver dans le dossier racine de notre "backend".
Le fichier ".babelrc" doit avoir le contenu suivant :

{
"presets": [
"@babel/preset-env"
]
}

 

Vous pouvez personnaliser les fonctionnalités de Babel dans ce formulaire de configuration. Vous pouvez par exemple configurer quelle version de navigateur doit être ciblée (commande : "cibles"). Si vous voulez en savoir plus sur ".babelrc" ou "babel.config.json" (pour les grands projets), veuillez consulter la documentation de "Babel":
https://babeljs.io/docs/en/config-files

Vous devez également modifier votre fichier "package.json" pour que "babel-watch" démarre automatiquement. Vous devez ajouter ce qui suit à votre fichier "package.json":

"scripts": {
"dev": "babel-watch server.js",
"build": "babel src -d build"
}

Cela crée également le raccourci de commande "dev" qui est lié à notre appel de programme "babel-watch". Vous pouvez maintenant utiliser le raccourci comme ceci : "npm run dev".
Si vous exécutez cette commande de raccourci, alors chaque modification enregistrée de notre fichier "server.js" est automatiquement convertie en un code rétrocompatible (compatible pour "NodeJS server").

 

Express framework - Backend

"Express" sera utilisé comme un intergiciel entre notre backend "NodeJS" et notre frontend "Angular". Vous devez installer la dépendance "express":

npm install express


Les "cors" de dépendance seront installés pour améliorer la sécurité de l'application. "body-parser" est utilisé pour analyser les "requêtes HTTP" entrantes dans notre serveur "Express".

npm install cors body-parser

Cette dépendance permet la configuration de CORS (Cross-Origin Resource Sharing), qui définit les noms de domaine externes pouvant être utilisés dans cette application. Les pirates ne peuvent donc pas injecter de scripts provenant d'autres sites, car avec les "cors", seuls certains sites ajoutés peuvent se connecter à cette application.

Il est maintenant temps de créer le fichier "server.js" avec le contenu suivant :

import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import bodyParser from 'body-parser';

const app = express();
const router = express.Router();

const DATABASE_CONNECTION = "mongodb://127.0.0.1/tasks";

app.use(cors());
app.use(bodyParser.json());

mongoose.connect(DATABASE_CONNECTION);
const connection = mongoose.connection;
connection.once("open", () => {
    console.log("Mongoose (MongoDB) database connection was created successfully!");
});

 

Ajoutez également le code qui met en place le serveur "Express"

app.use('/api', router);
app.listen(4000, () => console.log("Your Express server runs on the port 4000"));

 

Vous devez entrer votre adresse complète de serveur de base de données "mongodb" avec le nom de la base de données (ici : "tasks") dans la variable "DATABASE_CONNECTION". Ce code crée une connexion à la base de données de votre serveur "mongodb". Si la connexion a été établie avec succès, la chaîne ""Mongoose (MongoDB) database connection was created successfully !"" sera affichée.
Ensuite, le serveur "Express" écoute sur la page "/api" les "routes" accédées de notre "REST API" dans le serveur "Express". L'API sera créée ultérieurement.

Info : Si vous voulez héberger cette application sur "Heroku", utilisez le code suivant à la place:

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, 'public/index.html'));
});
const expressServerPort = process.env.PORT || 5000;
app.listen(expressServerPort, () => console.log("Express Server is currently running on the port " + expressServerPort));

 

MongoDB - La base de données Backend

Nous allons maintenant configurer la base de données de notre application. Si vous n'avez pas installé "mongodb", alors veuillez l'installer avec cette commande :
npm install mongoose

Dans "mongodb", il y a des "collections" qui sont l'équivalent de tables (en SQL). Une "collection" contient des documents qui sont l'équivalent de lignes (en SQL).
Une "collection" dans votre base de données "MongoDB" peut être ajoutée en créant un "schéma" dans votre application. Veuillez créer le dossier "modèle", qui contiendra les "schémas" de cette application.

Veuillez créer le fichier "Tasks.js" avec le contenu suivant:

 

import mongoose from 'mongoose';

const Schema = mongoose.Schema;

let Tasks = new Schema({
title: {
type: String,
required: [true, "Please enter a task title"]
},
description: {
type: String 
},
priority: {
type: Number,
default: 0
}
});

export default mongoose.model('Tasks', Tasks);

 

Ce "schéma" comporte un champ obligatoire "titre". Lorsque le champ obligatoire est vide, vous obtenez le message d'erreur défini. Le champ "priority" a une valeur par défaut de 0.

Veuillez importer ce "schéma" dans le fichier "server.js", car nous l'utiliserons pour accéder aux données dans la base de données de cette application:

import Tasks from './model/Tasks';

 

Création d'une API REST pour accéder aux données de la base de données

Vous pouvez créer une "API REST" en utilisant "routes" dans votre application "NodeJS". Vous utilisez les commandes "HTTP" "GET" et "POST" pour récupérer et envoyer les données de la base de données. On accède ensuite à cette "API REST" par le biais des "services angulaires", qui seront créés plus tard dans la partie "frontend" de ce tutoriel.

"HTTP GET" est utilisé ici pour interroger une ou plusieurs tâches particulières. Mais aussi pour supprimer une ou plusieurs tâches. Vous passez tous les arguments dans le lien URL (adresse complète).
Exemple : "/api/task/4" - "4" est l'identifiant de la tâche.

"HTTP POST" est utilisé pour enregistrer ou modifier une tâche. Toutes les valeurs et tous les arguments ne sont pas ajoutés dans l'URL. Mais ils sont ajoutés dans les données du site web ("formulaire HTML").

L'appel à la base de données se fait dans la commande "route". La classe de schéma importée est utilisée pour appeler une fonction "MongoDB". La fonction "MongoDB" obtient une fonction de rappel qui est appelée lorsque les données ont été renvoyées de la base de données. La programmation asynchrone est utilisée dans ce cas.

Veuillez créer les "routes" suivantes pour l'"API REST" de cette application. Ajoutez les codes suivants dans votre fichier "server.js":

Récupération de toutes les tâches

router.route("/tasks").get((req, res) => {
    Tasks.find((err, tasks) => {
        if (err) {
            console.log(err);
        } else {
            res.json(tasks);
        }
    });
});

 

Récupération d'une certaine tâche grâce à l'identifiant de la tâche:

router.route("/task/:id").get((req, res) => {
    Tasks.findById(req.params.id, (err, task) => {
        if (err) {
            console.log(err);
        } else {
            res.json(task);
        }
    });
});

 

La tâche peut être interrogée par le biais de la variable "_id" qui est la clé primaire de l'ensemble de données sauvegardées (row).


Ajout d'une nouvelle tâche

router.route('/task/add').post((req, res) => {
    let newTask = new Tasks(req.body);
    newTask.save()
        .then(task => {
            res.status(200).json("Task was added.");
        })
        .catch(err => {
            res.status(400).json("Error! Task could not be saved.");
            console.log(err);
        });
});

La tâche est créée dans le frontend "Angular" et ensuite passée ici comme en objet dans le "corps" des données "HTTP".

 

Mise à jour d'une tâche

router.route('/task/update/:id').post((req, res) => {
    Tasks.findById(req.params.id, (err, task) => {
        if (!task)
            res.status(400).json("The task that should be updated was not found.");
        else {
            task.title = req.body.title;
            task.description = req.body.description;
            task.priority = req.body.priority;

            task.save().then(task => {
                res.status(200).json("Task was successfully updated.");
            }).catch(err => {
                res.status(400).json("Error! Task could not be updated.");
                console.log(err);
            });
        }
    });
});

 

La tâche respective sera chargée à partir de la base de données par la commande "findById". Ensuite, le contenu de la tâche chargée est modifié et enregistré.


Supprimer toutes les tâches

router.route("/tasks/deleteall").get((req, res) => {
    Tasks.remove({}, (err) => {
        if (err) {
            res.status(400).json("Error. Tasks could not be deleted.");
            console.log(err);
        } else {
            res.status(200).json("Tasks were successfully deleted.");
        }
    });
});

 

Supprimer une certaine tâche

router.route("/task/delete/:id").get((req, res) => {
    Tasks.findByIdAndRemove({ _id: req.params.id }, (err, task) => {
        if (err) {
            res.status(400).json("Error! Task could not be deleted.");
            console.log(err);
        } else {
            res.status(200).json("Task was successfully deleted.");
        }
    });
});

Ce fut la création de l'"API REST" de cette application. Vous pouvez la tester avec n'importe quel client "REST API" tel que "Swagger UI" ou "Postman".

 

Angular - Frontend

Nous allons créer la vue en "HTML" et le code du programme frontal en "TypeScript". "Angular Material" est utilisé pour l'interface utilisateur (champs de saisie, tableau, style, etc.).

Mise en place de la configuration "angulaire

Nous utiliserons "Angular" pour le "frontend" de notre application. C'est pourquoi nous allons créer une application angulaire appelée "frontend".

ng new frontend

Suivez les instructions et cliquez sur "oui" lorsque vous êtes interrogé sur le "routage angulaire". Veuillez sélectionner "CSS" comme feuille de style.

Passez maintenant dans le dossier de votre nouvelle application " Angular ".

Nous devons maintenant ajouter nos dépendances " Angular " :

ng add @angular/material

Vous serez interrogé sur le thème de la conception de votre candidature et sur certains paramètres de conception.

 

Création des composants de notre application "Angular"

Une application web "angulaire" doit contenir des composants qui affichent le contenu de l'application web. Par exemple, vous avez un composant qui affiche vos coordonnées, un composant pour lister vos tâches, etc.

Nous allons créer ces composants qui sont nécessaires pour notre application "CRUD".

 

ng g c components/view

Composant qui affiche les tâches. Cette commande est l'abréviation de la commande "ng generate component components/view" (ng générer les composants du composant / afficher)

ng g c components/create

Composante qui crée des tâches.

 

ng g c components/edit

 

Composant qui édite les tâches.

 

Nous devons maintenant ajouter le "routage" de notre application. Celui-ci définit le lien qui est utilisé pour accéder à un certain "composant" dans notre application "Angulaire".

Allez dans votre fichier "app-routing.module.ts". Le fichier est situé dans le chemin "src/app".
Et ajoutez le contenu suivant :

const routes: Routes = [
{ path: 'view', component: ViewComponent },
{ path: 'edit/:id', component: EditComponent },
{ path: 'list', component: ListComponent },
{ path: '', redirectTo: '/list', pathMatch: 'full'}
];

 

Vous pouvez importer des modules "Angulaires" dans le fichier "app.module.ts".
Nous utiliserons pour cette application le module "MatToolbar". Le module peut être importé avec ces commandes :
Ajoutez cette déclaration d'importation en haut de ce fichier:

import { MatToolbarModule } from '@angular/material/toolbar';


Vous devez également ajouter le module dans la section "importation":

imports: [
... 
MatToolbarModule 
...
]

 

Nous devons également ajouter le module "HttpClientModule" qui est nécessaire pour accéder à notre "REST API" dans notre serveur "Express".
Veuillez l'ajouter également dans notre "app.module.ts":

import { HttpClientModule } from '@angular/common/http';

 

imports: [
...
HttpClientModule
...
]

 

Les composants de votre application sont ajoutés dans la balise "<router-outlet>" de votre fichier "app.component.html".

Nous allons créer le fichier "app.component.html" suivant:

 

<mat-toolbar>
  <span class="appTitle">MEAN Stack CRUD Example APP - Tasks</span>
  <br>
  <br>
</mat-toolbar>
<h4 class="centered-text">This is a demo app.</h4>

<div>
  <router-outlet></router-outlet>
</div>

 

Il s'agit de la racine de votre application web frontale et d'un composant. Chaque composant possède un fichier "html" et un fichier "CSS" qui modifient l'interface de votre composant. Mais aussi un fichier ".ts" qui définit le code de programmation (logique métier) d'un composant.

Notre racine "app.component" possède également un fichier "css" personnalisé. Veuillez ajouter ce qui suit à votre fichier "app.component.css":

.appTitle{
    font-size: 16px;
    color: orange;
}
.centered-text{
    text-align: center;
    font-size: 15px;
    font-weight: bold;
    margin: 10px;
    color: red;
}

 

Créer le "Service" de notre application Angular

Il est maintenant temps de créer un "Angular Service" pour accéder aux données de notre base de données. Cela peut être fait avec cette commande :

ng g s Tasks

Cette commande est une abréviation de la commande "ng generate service". Si vous avez utilisé le nom " Tasks ", alors le " service angulaire " est appelé " TasksService ".

Vous devez importer le "Service angulaire" créé dans le fichier "app.module.ts" :

import { TasksService } from './tasks.service';

 

Ajoutez également ceci dans le fichier "app.module.ts":

  providers: [TasksService],

 

Ajouter ce qui suit au nouveau "Service des tâches" créé :

 

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class TasksService {

API_URL = "http://127.0.0.1:4000/api";

  constructor(private httpClient: HttpClient) { }

}

"API_URL" a l'adresse complète de notre serveur "Express" et "REST API". Vous devez maintenant ajouter des fonctions de création pour toutes les "routes" qui ont été définies dans notre "REST API" dans le "backend".
Ajoutez les fonctions suivantes à votre "TasksService" :

//Call the "REST API" to get a certain task through the task id
  getTaskById(id) {
    return this.httpClient.get(`${this.API_URL}/task/${id}`);
  }

//Returns all tasks in the database
  getTasks() {
    return this.httpClient.get(`${this.API_URL}/tasks`);
  }

//Creates a new task object and send it to the "REST API" to save it
  addTask(title, description, priority) {
    const newTask = {
      title: title,
      description: description,
      priority: priority
    };
    return this.httpClient.post(`${this.API_URL}/task/add`, newTask);
  }
  
//Creates a new task object and send task id and task object to the "REST API" to update it
  updateTask(id, title, description, priority) {
    const updatedTask = {
      title: title,
      description: description,
      priority: priority
    };
    return this.httpClient.post(`${this.API_URL}/task/update/${id}`, updatedTask)
  }

//Delete task - Returns only info or error message
  deleteTaskById(id) {
    return this.httpClient.get(`${this.API_URL}/task/delete/${id}`);
  }
  
//Delete all tasks - Returns only info or error message
  deleteAllTasks() {
    return this.httpClient.get(`${this.API_URL}/task/deleteall`);
  }

Vous pouvez maintenant utiliser ce "Service angulaire" "Task Services" lorsque vous l'importez et l'ajoutez comme variable (l'injecter) dans le constructeur de votre classe de composants.
Ceci sera fait plus tard dans ce tutoriel.

Mise en œuvre des composantes "angulaires" créées

Nous arrivons maintenant à la dernière partie de ce tutoriel. Vous devez maintenant ajouter les "Modules angulaires" que nous utiliserons dans nos "Composants angulaires".
Veuillez ajouter ce qui suit dans votre fichier "app.module.ts":

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatTableModule } from '@angular/material/table';
import { MatDividerModule } from '@angular/material/divider';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatSliderModule } from '@angular/material/slider'; 
import { MatPaginatorModule } from '@angular/material/paginator'; 

  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatToolbarModule,
	FormsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatIconModule,
    MatButtonModule,
    MatCardModule,
    MatTableModule,
    MatDividerModule,
    MatSnackBarModule,
    MatSliderModule,
	MatPaginatorModule
  ],

 

Vous devez créer une classe "TypeScript" pour le "schéma MongoDB" "Tâches". Ceci est nécessaire pour faire correspondre l'objet "MongoDB" à un objet "Javascript".
Créez le fichier "tasks.model.ts" avec le contenu suivant :

 

export interface Tasks {
    id: String;
    title: String;
    description: String;
    priority: Number;
}

 

Maintenant, vous devez implémenter tous les composants créés avec les contenus suivants :

ViewComponent

Cette composante affichera les tâches dans un tableau. Il y a un bouton d'édition et de suppression pour chaque tâche du tableau.

Classe de composant de type "view.component.ts" :

import { Component, OnInit } from '@angular/core';
import { TasksService } from 'src/app/tasks.service';
import { Router } from '@angular/router';
import { Tasks } from 'src/tasks.model';
import { MatSnackBar } from '@angular/material/snack-bar';

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrls: ['./view.component.css']
})
export class ViewComponent implements OnInit {

  tasks: Tasks[];
  tableColumns = ['title', 'description', 'priority', 'edit'];

  constructor(private snackBar: MatSnackBar, private tasksService: TasksService, private router: Router) { 
    this.loadTasks();
  }

  ngOnInit(): void {
  }

  loadTasks() {
    this.tasksService.getTasks().subscribe((tasksData: Tasks[]) => {
      this.tasks = tasksData;
    });
  }

  editTask(id) {
    this.router.navigate([`/edit/${id}`]);
  }

  deleteTask(id) {
    this.tasksService.deleteTaskById(id).subscribe(() => {
      this.loadTasks();
      this.snackBar.open("Task was deleted.", "OK", {
        duration: 4000
      });
    })
  }
}

 

Fichier HTML "view.component.html":

<div>
    <br>
    <mat-card>
        <button mat-raised-button color="primary" routerLink="/create">Add new task</button>
        <br><br>
        <mat-divider></mat-divider>
        <br>
        <h3>All Tasks</h3>
        <br>
        <table mat-table [dataSource]="tasks">
            <ng-container matColumnDef="title">
                <th mat-header-cell *matHeaderCellDef> Title </th>
                <td mat-cell *matCellDef="let element"> {{element.title}} </td>
            </ng-container>

            <ng-container matColumnDef="description">
                <th mat-header-cell *matHeaderCellDef> Description </th>
                <td mat-cell *matCellDef="let element"> {{element.description}} </td>
            </ng-container>

            <ng-container matColumnDef="priority">
                <th mat-header-cell *matHeaderCellDef> Priority </th>
                <td mat-cell *matCellDef="let element"> {{element.priority}} </td>
            </ng-container>

            <ng-container matColumnDef="edit">
                <th mat-header-cell *matHeaderCellDef class="mat-column-right"> Actions </th>
                <td mat-cell *matCellDef="let element" class="mat-column-right">
                    <button mat-button color="primary" (click)="editTask(element._id)">Edit</button>
                    <button mat-button color="warn" (click)="deleteTask(element._id)">DELETE</button>
                </td>
            </ng-container>

            <tr mat-header-row *matHeaderRowDef="tableColumns"></tr>
            <tr mat-row *matRowDef="let row; columns: tableColumns;"></tr>

            <mat-paginator [length]="500" [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 100, 500]">
            </mat-paginator>
        </table>

        <div *ngIf="tasks == null || tasks.length < 1">
            <h4 class="noTasksInfo">You have no tasks!</h4>
        </div>

    </mat-card>
</div>

La commande " ng-container matColumnDef="actions" " définit la colonne de notre tableau. Toutes les lignes de notre tableau sont alors affichées à l'aide de cette commande " mat-row *matRowDef="let row ; columns : tableColumns ;" ".
"*ngIf" est utilisé pour décider, grâce au code "TypeScript", d'afficher ou non une certaine "balise HTML".

 

Fichier CSS "view.component.css" :

table {
    width: 100%
}

.mat-column-right {
    text-align: center;
}

 

CreateComponent

Ce composant est utilisé pour sauvegarder une tâche. Un module "formulaire" est utilisé pour réaliser cela.

Classe de composant typographique "create.component.ts" :

import { Component, OnInit } from '@angular/core';
import { TasksService } from 'src/app/tasks.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { MatSnackBar } from '@angular/material/snack-bar';

@Component({
  selector: 'app-create',
  templateUrl: './create.component.html',
  styleUrls: ['./create.component.css']
})
export class CreateComponent implements OnInit {

  createTaskForm: FormGroup;
  priorityValue = 0;

  constructor(private snackBar: MatSnackBar, private tasksService: TasksService, private formBuilder: FormBuilder, private router: Router) {
    this.createTaskForm = this.formBuilder.group({
      title: ['', Validators.required],
      description: '',
      priority: 0
    });
  }

  ngOnInit(): void {
  }

  createTask(title, description, priority) {
    this.tasksService.addTask(title, description, priority).subscribe(() => {
      this.router.navigate(['/']);
      this.snackBar.open("OK. Task was added.", "OK", {
        duration: 4000
      });
    })
  }

}

 

Fichier HTML "create.component.html":

<div>
    <br>
    <mat-card>
        <br>
        <h3>Add A New Task</h3>
        <mat-divider></mat-divider>
        <br>
        <form [formGroup]="createTaskForm" class="create-task-form">
            <mat-form-field class="column-full-width">
                <input matInput placeholder="Task Title" formControlName="title" #title>
            </mat-form-field>

            <mat-form-field class="column-full-width">
                <input matInput placeholder="Task Description" formControlName="description" #description>
            </mat-form-field>

            <div class="column-full-width">
                <h4>Priority: </h4>
                <mat-slider thumbLabel tickInterval="1" min="1" max="10" [(ngModel)]="priorityValue" formControlName="priority" #priority>
                </mat-slider>
            </div>

            <mat-divider></mat-divider>
            <br><br>
            <button class="saveButton" type="submit" (click)="createTask(title.value, description.value, priority.value)"
                [disabled]="createTaskForm.pristine || createTaskForm.invalid" mat-raised-button
                color="primary">Save</button>
            <button mat-raised-button color="accent" routerLink="/">Back</button>
        </form>
    </mat-card>
</div>

 

La commande "" [disabled]="createTaskForm.pristine || createTaskForm.invalid" "" désactive le bouton d'envoi lorsqu'au moins un champ de texte n'a pas été cliqué ou que des données incorrectes sont présentes dans les champs de texte.
"[(ngModel)]" est utilisé pour définir la valeur d'un élément "angulaire" de l'interface utilisateur.

 

Fichier CSS "create.component.css":

.create-task-form {
    min-width: 160px;
    width: 100%;
}

.column-full-width {
    width: 100%;
}

.saveButton{
    margin-right: 15px;
}

 

EditComponent

Ce composant est utilisé pour éditer une tâche. Un module "formulaire" est utilisé pour réaliser cela.

Classe de composant typographique "edit.component.ts":

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { TasksService } from 'src/app/tasks.service';
import { MatSnackBar } from '@angular/material/snack-bar';

@Component({
  selector: 'app-edit',
  templateUrl: './edit.component.html',
  styleUrls: ['./edit.component.css']
})
export class EditComponent implements OnInit {


  id: String;
  task: any = {};
  updateTaskForm: FormGroup;
  priorityValue = 0;

  constructor(private tasksService: TasksService,private router: Router, private route: ActivatedRoute, private snackBar: MatSnackBar, private formBuilder: FormBuilder ) {
    this.loadEditTaskForm();
   }

  ngOnInit(): void {
    this.route.params.subscribe(params => {
      this.id = params.id;
      this.tasksService.getTaskById(this.id).subscribe(res => {
        this.task = res;
        this.updateTaskForm.get("title").setValue(this.task.title);
        this.updateTaskForm.get("description").setValue(this.task.description);
        this.priorityValue = this.task.priority;
      });
    });
  }
  
  loadEditTaskForm(){
    this.updateTaskForm = this.formBuilder.group({
      title: ['', Validators.required],
      description: '',
      priority: 0
    });
  }

  editTask(title, description, priority){
    this.tasksService.updateTask(this.id, title, description, priority).subscribe(() => {
      this.router.navigate(['/']);
      this.snackBar.open('Task was updated successfully.', 'OK', {
        duration: 3000
      });
    });
  }
}

 

Fichier HTML "edit.component.html":

<div>
    <br>
    <mat-card>
        <h3>Edit Task</h3>
        <mat-divider></mat-divider>
        <br>
        <form [formGroup]="updateTaskForm" class="edit-task-form">
            <mat-form-field class="column-full-width">
                <input matInput placeholder="Task Title" formControlName="title" #title>
            </mat-form-field>

            <mat-form-field class="column-full-width">
                <input matInput placeholder="Task Description" formControlName="description" #description>
            </mat-form-field>

            <div class="column-full-width">
                <mat-slider thumbLabel tickInterval="1" min="1" max="10" [(ngModel)]="priorityValue" formControlName="priority" #priority></mat-slider>
            </div>

            <mat-divider></mat-divider>
            <br><br>
            <button class="saveButton" type="submit" (click)="editTask(title.value, description.value, priority.value)" mat-raised-button
            color="primary">Save</button>
            <button mat-raised-button color="accent" routerLink="/">Back</button>
        </form>
    </mat-card>
</div>

 

Fichier CSS "edit.component.css":

.edit-task-form {
    min-width: 160px;
    width: 100%;
}

.column-full-width {
    width: 100%;
}

.saveButton{
    margin-right: 15px;
}

 

La création de cette application est maintenant terminée.

Si vous voulez démarrer cette application, exécutez ces 2 commandes dans des terminaux séparés :
Dans le dossier "backend":

npm run dev

 

Dans le dossier "frontend":

ng serve --open

 

Si vous voulez construire cette application pour l'héberger sur un serveur web (utilisation en production), utilisez ces commandes :
Allez dans le dossier "backend". Copiez tous vos fichiers JavaScript dans le dossier "src". Ensuite, lancez cette commande :

npm run build

 

Dans le dossier "frontend" :

ng build --prod

 

C'était une introduction à la création d'une application "MEAN stack" avec la fonctionnalité "CRUD". Vous pouvez également ajouter toute une série de fonctionnalités à l'aide du gestionnaire de paquets "npm" et des "modules angulaires".

Cette application sur Github:
https://github.com/a-dridi/mean_crud_example

En savoir plus sur MongoDB:
https://docs.mongodb.com/manual/core/databases-and-collections/

REST API Client - Swagger UI:
https://swagger.io/tools/swagger-ui/

REST API Client - Postman:
https://www.postman.com/

Angular Material:
https://material.angular.io/

Angular:
https://angular.io/docs

NodeJS:
https://nodejs.org/en/docs/

Catégorie :

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.

Ok