diff --git a/docs/getari.md b/docs/getari.md new file mode 100644 index 0000000000000000000000000000000000000000..7780bb3844bcd1bc685df9ca1808fa17d6418535 --- /dev/null +++ b/docs/getari.md @@ -0,0 +1,179 @@ +# Sommaire +[//]: # (Navigation not working with mkdocs) + +1. [Le fonctionnement théorique](#Le-fonctionnement-théorique) +2. [Le fonctionnement du code](#Le-fonctionnement-du-code) +3. [Le fonctionnement des menus déroulants (MenuItems)](#Le-fonctionnement-des-menus) +4. [Le rechargement d'un état sauvegardé](#Le-rechargement) +5. [Les problèmes connus](#Les-problèmes-connus) +6. [Les méthodes](#Les-méthodes) + +# Fonctions Annuler / Récupérer + +## Le fonctionnement théorique + + + +Un point de sauvegarde se crée et vous pouvez ainsi annuler ou récupérer les événements passés lorsque vous effectuez +une action: + +- Modifier le nom de l'évaluation. +- Ajouter/supprimer/modifier un indicateur. +- Ajouter/supprimer/modifier un processus. +- Modifier le paramètrage d'une agrégation. + +Bouton annuler (Undo): + +- Annule l'état actuel et recharge l'état précédent (CTRL + Z ou en cliquant sur la flèche retour). +- Annule l'état sélectionné dans le menu déroulant et recharge l'état précédent. + Tous les éléments situés entre l'état actuel et l'état sélectionné dans le menu déroulant seront récupérable par ordre + d’exécution dans la liste **Récupérer**. + +Bouton récupérer (Redo): + +- Récupère l'état qui vient d'être annulé et le recharge (CTRL + Y ou en cliquant sur la flèche avant). +- Récupère l'état sélectionné dans le menu déroulant et le recharge. + Tous les éléments situés entre l'état actuel et l'état sélectionné dans le menu déroulant seront de nouveau annulable + par ordre d'exécution dans la liste **Annuler**. + +> [Sommaire](#Sommaire) + +## Le fonctionnement du code + +La sauvegarde de l'état actuel se fait grâce à la classe Memento. +On crée un objet Memento qui prend l'évaluation actuelle en paramètre, ainsi que son état et un ID. +[//]: # (block code design can be upgraded) + + final Evaluation e = GetariApp.get().getCurrentEval().clone(); + int newID = history.getMemento().getId() + 1; + Memento m = new Memento(e, Messages.getString("msg", indicator.getName()), newID); + history.addMemento(m); + +Chaque action crée un objet Memento et le stock en première position dans une liste observable de la classe History: la +liste undo. Chaque ajout vide la deuxième liste (redo) . +Cette classe History possède deux liste observable qui géreront les éléments à annuler, et ceux à récupérer. + +Lors du clique sur le bouton **Annuler**, la méthode undo() de la classe History est appelée. +Cette méthode transfert le premier élément de la liste undo vers la liste redo et recharge le nouveau premier élément de +la liste undo (qui est en fait l'état précédent). + +Lors du clique sur le bouton **Récupérer**, la méthode redo() de la classe History est appelée. +Cette méthode transfert le premier élément de la liste redo vers la liste undo en première position et recharge le +premier élément de la liste undo. + +Lors du clique sur un des éléments du menu déroulant du bouton **Annuler**, la méthode undoByID(int id) de la classe +History est appelée. +Cette méthode prend un argument un Integer et cherche dans la liste undo le mémento qui possède cet ID grâce à la +méthode findByID(int id). +Puis, à partir du premier élément jusqu’à celui possédant l'ID, transfert tous les éléments de la liste undo vers la +liste redo par ordre d'exécution. +Enfin, recharge le premier élément de la liste undo. + +Lors du clique sur un des éléments du menu déroulant du bouton **Récupérer**, la méthode redoByID(int id) de la classe +History est appelée. +Cette méthode prend un argument un Integer et cherche dans la liste redo le mémento qui possède cet ID grâce à la +méthode findByID(int id). +Puis, à partir du premier élément jusqu’à celui possédant l'ID, transfert tous les éléments de la liste redo vers la +liste undo par ordre d'exécution. +Enfin, recharge le premier élément de la liste undo. + +> [Sommaire](#Sommaire) + +## Le fonctionnement des menus + + + +Les listes observables de la classe History ont chacune un EventListener qui se déclenche quand la taille de la liste +change. +Plusieurs événements se déclenchent. +Quand la taille de la liste undo history **augmente** mais que la redo history est toujours **vide**: + +- Un MenuItem 'item' se crée en prenant le nom du mémento (son "état"). +- Un listener est ajouté sur cet item qui déclenchera la méthode undoByID(int id) si il est cliqué. +- Cet item est ajouté dans une ArrayList nommée 'undoList'. +- Cette liste est ajoutée au bouton undoBtn pour l'affichage du menu déroulant. + +Quand la taille de la liste undo history **diminue**: + +- Un MenuItem 'item' se crée en prenant le nom du mémento (son "état"). +- Un listener est ajouté sur cet item qui déclenchera la méthode redoByID(int id) si il est cliqué. +- Cet item est ajouté dans une ArrayList nommée 'redoList'. +- Cette liste est ajoutée au bouton redoBtn pour l'affichage du menu déroulant. +- Le premier item de la undoList est supprimé. + +Quand la taille de la liste redo history **diminue**: + +- Un MenuItem 'item' se crée en prenant le nom du mémento (son "état"). +- Un listener est ajouté sur cet item qui déclenchera la méthode undoByID(int id) si il est cliqué. +- Cet item est ajouté dans la undoList en première position. +- Cette liste est ajoutée au bouton redoBtn pour l'affichage du menu déroulant. +- Le premier item de la redoList est supprimé. +- Si la liste redo history est vide, clear() également la redoList. +- + +> [Sommaire](#Sommaire) + +## Le rechargement + +Lors de l'utilisation des boutons annuler/récupérer, la méthode reloadGraph() de la classe GraphView est appelée. Cette +méthode vide les panneaux, récupère le dernier mémento de la liste undo history. +L’évaluation associée à ce mémento est extraite, clonée, puis rechargée. + +> [Sommaire](#Sommaire) + +## Les problèmes connus + +Lors d'un trop grand nombre d'annulations, récupérations, ajouts/suppressions d'indicateurs, Getari crash. + +`#1 Exception in thread "JavaFX Application Thread" java.lang.OutOfMemoryError: Required array length too large` +`#2 Exception in thread "JavaFX Application Thread" java.lang.OutOfMemoryError: Java heap space` +Ce problème est certainement dû au clonage de l'évaluation. + +L'ajout d'une fonction d'agrégation déclenche bien le point de sauvegarde, mais le rechargement n'annule pas cet ajout. + +Incapacité à localiser l'endroit où placer certains points de sauvegarde pour la modification de certains indicateurs ( +Normalisation, Seuil, Linéaires). +Incapacité à sauvegarder après avoir cliquer sur le bouton "Tout effacer" car ce bouton appelle la méthode clearGraph() +de GraphView qui est elle même appelée à chaque rechargement d'un événement passé. + +> [Sommaire](#Sommaire) + +## Les méthodes + +***Classe ToolbarController*** + +| Nom | Fonctionnement | +|---------------------|-------------------------------------------------| +| setHistory(history) | Ajoute un listener sur les listes undo et redo | +| onUndoAction(event) | Déclenche les méthode undo() et reloadCmd.run() | +| onRedoAction(event) | Déclenche les méthode redo() et reloadCmd.run() | +| initialize() | Ajoute le tooltip et le hover sur les boutons | + +--- +***Classe History*** + +| Nom | Fonctionnement | +|---------------------|----------------------------------------------------------------------------------------------------------| +| addMemento(memento) | Ajoute un memento dans la liste undoHistory | +| undo() | Transfert le premier élément de la liste undo vers la liste redo | +| redo() | Transfert le premier élément de la liste redo vers la liste undo | +| undoById(int) | Transfert tous les éléments depuis le premier jusqu'au mémento voulu de la liste undo vers la liste redo | +| redoById(int) | Transfert tous les éléments depuis le premier jusqu'au mémento voulu de la liste redo vers la liste undo | +| findById(int) | Retourne le mémento correspondant à l'ID dans la liste undo | +| findRedoById(int) | Retourne le mémento correspondant à l'ID dans la liste redo | +| getUndoMemento() | Retourne le mémento en première position de la liste undo | +| getRedoMemento() | Retourne le mémento en première position de la liste redo | + +--- +***Classe GraphView*** + +| Nom | Fonctionnement | +|---------------------------------|---------------------------------------------------------------------------------------------------------------| +| reloadGraph() | Nettoie les panneaux et les rechargent avec l'évaluation voulue. | +| configureUndoRedoButtons(stage) | Ajoute un listener sur le stage pour écouter la combinaison de touche CTRL+Z et CTRL+Y pour undo() et redo(). | + +> [Sommaire](#Sommaire) + + + + diff --git a/docs/index.md b/docs/index.md index 1ee522962f5d39897269f0c349abcb2998f28099..9daead09b685ee576db3bce6446afd47c7c69f7f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,8 @@ This is an inline image:  symbols. +[//]: # (not rendered properly by mkdocs) Like this: ~~Strikethrough text~~ # Task Lists @@ -36,14 +37,17 @@ Like this: ~~Strikethrough text~~ Task lists allow you to create a checklist of items with checkboxes. Uncompleted tasks: +[//]: # (not rendered properly by mkdocs) - [ ] Task 1 - [ ] Task 2 - [ ] Task 3 Completed task: +[//]: # (not rendered properly by mkdocs) - [x] Task 1 Nested task list: +[//]: # (not rendered properly by mkdocs) - [ ] Task 1 - [ ] Subtask 1.1 - [x] Subtask 1.2 diff --git a/docs/reactive-programming.md b/docs/reactive-programming.md new file mode 100644 index 0000000000000000000000000000000000000000..734caea5a9603207f8b5e5333740db50b3d3b493 --- /dev/null +++ b/docs/reactive-programming.md @@ -0,0 +1,304 @@ +# What is Reactive Programming in Angular with RXJS + +## Introduction + +### Definition of Reactive Programming + +Reactive programming is a programming paradigm that is based on the idea of data streams and functional programming. In reactive programming, data streams are represented as events that can be observed, transformed, and combined to create new streams of data. This allows developers to build applications that are more responsive and scalable than traditional imperative programming. + +### Explanation of why Reactive Programming is important in Angular + +Reactive programming is important in Angular because it allows developers to build applications that are more responsive and scalable. Reactive programming enables developers to build applications that can handle complex and asynchronous events in real-time, which is essential for building modern web applications. +### Overview of RXJS library + +One of the key libraries used for reactive programming in Angular is the RXJS library. RXJS is a reactive programming library that is used to build complex and dynamic applications. It provides a set of powerful tools for working with data streams, including Observables, Operators, and Subjects. + +Observables are a fundamental concept in RXJS that represent a data stream over time. They can be used to represent asynchronous data streams, such as HTTP requests or user events. Operators are functions that can be used to transform or filter data streams, allowing developers to create new streams of data from existing ones. Subjects are a way of sharing data between different parts of an application, allowing developers to create more modular and flexible code. + +In summary, reactive programming in Angular with RXJS is a powerful paradigm that allows developers to build complex and dynamic applications. By using observables, operators, and subjects, developers can build applications that are more responsive, scalable, and maintainable than traditional imperative programming. + +## What is RXJS? + +### Explanation of RXJS library + +RXJS is a library for reactive programming that is based on the Observable pattern. Observables are data streams that can be observed and transformed over time. RXJS provides a set of powerful tools for working with observables, including operators and subjects. It allows developers to build complex and dynamic applications that are responsive to user input and data changes. +### Comparison with traditional event-driven programming + +Traditionally, event-driven programming is used for building dynamic applications. In event-driven programming, an event occurs and triggers a callback function that handles the event. This can quickly become complex and difficult to maintain, especially in large applications. RXJS provides a more elegant and maintainable solution for building dynamic applications by using observables and operators. +### Benefits of using RXJS in Angular + +One of the key benefits of using RXJS in Angular is that it enables developers to write more declarative and expressive code. Observables and operators provide a powerful and intuitive way of working with data streams, making it easier to write clean and concise code. RXJS also provides a set of powerful tools for handling asynchronous operations, such as HTTP requests and user input. + +Another benefit of using RXJS in Angular is that it provides a consistent and modular approach to handling data streams. Observables and subjects can be used to create reusable components and services that can be easily combined and composed. This makes it easier to build large and complex applications that are easier to maintain and extend. +### Key concepts in RXJS, including Observables, Operators, and Subjects + +Observables are a fundamental concept in RXJS. They represent a data stream over time, and can be used to represent asynchronous data streams, such as HTTP requests or user input. Operators are functions that can be used to transform or filter data streams, allowing developers to create new streams of data from existing ones. Subjects are a way of sharing data between different parts of an application, allowing developers to create more modular and flexible code. + +In summary, RXJS is a powerful library for reactive programming that is widely used in Angular for building complex and dynamic applications. By using observables, operators, and subjects, developers can build applications that are more expressive, modular, and maintainable than traditional event-driven programming. + +## Reactive Programming in Angular + +### Explanation of how Reactive Programming is used in Angular + +In Angular, reactive programming is used to manage and manipulate data streams over time. This is typically done using the RXJS library, which provides a set of powerful tools for working with observables, operators, and subjects. Observables represent a stream of data over time, while operators are used to manipulate that data in various ways. Subjects are used to share data between different parts of the application. + +Reactive programming is used throughout Angular to handle asynchronous operations, such as HTTP requests and user input. By using reactive programming, developers can write more declarative and expressive code that is easier to understand and maintain. + +### Comparison with traditional imperative programming + +Traditionally, imperative programming has been used for building dynamic applications. In imperative programming, the application state is modified directly through imperative statements. This can quickly become complex and difficult to maintain, especially in large applications. Reactive programming provides a more elegant and maintainable solution for building dynamic applications by using observables, operators, and subjects. + +Reactive programming is declarative, which means that the developer specifies what should happen, rather than how it should happen. This makes it easier to understand and maintain the code, especially as the application becomes more complex. + +### Key benefits of using Reactive Programming in Angular + +There are several key benefits of using reactive programming in Angular. Firstly, reactive programming makes it easier to handle asynchronous operations, such as HTTP requests and user input. By using observables and operators, developers can handle asynchronous operations in a more elegant and maintainable way. + +Secondly, reactive programming makes it easier to write modular and reusable code. Observables and subjects can be used to create reusable components and services that can be easily combined and composed. This makes it easier to build large and complex applications that are easier to maintain and extend. + +Finally, reactive programming makes it easier to reason about the behavior of the application. By using reactive programming, developers can write code that is more declarative and expressive, making it easier to understand how the application will behave under different conditions. + +### Example use cases in Angular + +There are many example use cases for reactive programming in Angular. One common use case is handling user input, such as form submissions. Reactive programming can be used to create observables that represent the form data, and operators can be used to transform and validate the data. + +Another example use case is handling asynchronous operations, such as HTTP requests. Reactive programming can be used to create observables that represent the HTTP requests, and operators can be used to transform and handle the response data. + +#### Implementation of a search input + +Here's an example of how to implement a search input in Angular using Reactive Forms and RxJS to make the search reactive: + +First, we need to create a Reactive Form in our component. We'll add a `FormControl` to track the value of our search input: + + +```typescript +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; + +@Component({ + selector: 'app-search', + template: ` + <input type="text" [formControl]="searchInput" placeholder="Search"> + <ul> + <li *ngFor="let result of searchResults">{{ result }}</li> + </ul> + `, +}) +export class SearchComponent { + searchInput = new FormControl(''); + searchResults$ = new Observable<string[]>(); +} +``` + +Next, we'll use RxJS to make our search reactive. We'll use the valuechanges observable from the FormControl to track the value of the search input and use the `debounceTime` operator to delay the search until the user has finished typing: + +```typescript +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, switchMap } from 'rxjs/operators'; + +@Component({ + selector: 'app-search', + template: ` + <input type="text" [formControl]="searchInput" placeholder="Search"> + <ul> + <li *ngFor="let result of searchResults$ | async">{{ result }}</li> + </ul> + `, +}) +export class SearchComponent { + searchInput = new FormControl(''); + + searchTerm$ = this.searchInput.valueChanges.pipe( + debounceTime(300), // wait for user to stop typing for 300ms + distinctUntilChanged(), // ignore repeated search terms + ); + searchResults$ = this.searchTerm$.pipe( + // switch to new observable for each search term + switchMap((term: string) => this.fakeBackendSearch(term)) + ); + + private fakeBackendSearch(term: string): Observable<string[]> { + // Implement your fake backend search here and return an Observable of results + } +} +``` + +#### Implementation of a search input with filtered and sorted result + +Suppose we have 3 observables - `searchTerm$`, `filter$`, and `sort$`, and we want to combine them to get a single observable called `result$` that will emit the filtered and sorted search results based on the latest values of `searchTerm$`, `filter$`, and `sort$`. + + + +```typescript +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +export class SearchComponent { + searchTerm$ = new BehaviorSubject<string>(''); + filter$ = new BehaviorSubject<string>('all'); + sort$ = new BehaviorSubject<string>('relevance'); + + result$ = combineLatest([this.searchTerm$, this.filter$, this.sort$]).pipe( + map(([searchTerm, filter, sort]) => { + // Call the search service with the latest values of searchTerm, filter, and sort + return this.searchService.search(searchTerm, filter, sort); + }) + ); +} +``` + +In this example, we first import the `combineLatest` operator and the `map` operator from the `rxjs/operators` module. We also import the `BehaviorSubject` class from the `rxjs` module. + +We then define three BehaviorSubjects - `searchTerm$`, `filter$`, and `sort$` - to hold the latest values of the search term, filter, and sort criteria respectively. + +Then we create a new observable called `result$` by calling the `combineLatest` operator and passing in an array of the three BehaviorSubjects. The `combineLatest` operator emits an array of the latest values of `searchTerm$`, `filter$`, and `sort$` whenever any one of them changes. + +We then use the `map` operator to transform the emitted array into the search results by calling the `search` method of the `SearchService` with the latest values of `searchTerm`, `filter`, and `sort`. + +Finally, we can use the `result$` observable in our view as a model to display the filtered and sorted search results based on the latest values of `searchTerm$`, `filter$`, and `sort$`. + + + +## Key Concepts in Reactive Programming with RXJS + +### Definition and explanation of Observables + +Observables represent a stream of data over time. They can emit zero or more values, and can either complete or error. Observables are often used to handle asynchronous operations, such as HTTP requests and user input, where the data may not be available immediately. + +Observables are similar to promises in that they represent a future value, but observables are more powerful because they can emit multiple values over time, whereas promises can only emit a single value. + +### Creation and subscription of Observables + +Observables can be created using several methods in RXJS, including the `of` and `from` methods. The `of` method creates an observable that emits a sequence of values, while the `from` method creates an observable from an array, iterable, or promise. + +Once an observable is created, it must be subscribed to in order to receive the emitted values. This is done using the `subscribe` method. The `subscribe` method takes three arguments: a callback function to handle the emitted values, a callback function to handle errors, and a callback function to handle completion. + +### Example use cases in Angular + +Observables are used throughout Angular to handle asynchronous operations, such as HTTP requests and user input. Here are some example use cases for observables in Angular: + +```typescript +import { HttpClient } from '@angular/common/http'; + +constructor(private http: HttpClient) {} + +ngOnInit() { + this.http.get('https://api.example.com/data').subscribe((data) => { + console.log(data); + }, (error) => { + console.error(error); + }); +} +``` + +#### User input + +User input in Angular can be handled using observables created from DOM events, such as the `click` or `input` events. Developers can subscribe to these observables to receive the event data and handle any errors. + +```typescript +import { fromEvent } from 'rxjs'; + +ngOnInit() { + const button = document.querySelector('button'); + const click$ = fromEvent(button, 'click'); + + click$.subscribe((event) => { + console.log('Button clicked!'); + }, (error) => { + console.error(error); + }); +} +``` + +In summary, observables are a key concept in reactive programming with RXJS in Angular. They represent a stream of data over time, and can be created and subscribed to in order to handle asynchronous operations. By using observables, developers can build more powerful and maintainable applications in Angular. + +### Subjects + +### Definition and explanation of Subjects + +Subjects are a type of observable that allows for both subscribing and emitting values. They can be thought of as a bridge between observables and other types of data sources, such as event emitters or even other observables. Subjects have two key methods: `next`, which is used to emit a value, and `subscribe`, which is used to subscribe to the subject and receive the emitted values. + +There are four types of subjects in RXJS: `BehaviorSubject`, `ReplaySubject`, `AsyncSubject`, and `Subject`. Each type of subject has its own specific use case and behavior. + +### Example use cases in Angular + +Subjects are used throughout Angular to handle data communication between components and services. Here are some example use cases for subjects in Angular: + +#### Sharing data between components + +Subjects can be used to share data between components that are not directly related to each other. This can be useful in situations where multiple components need to access the same data or need to communicate with each other. + +```typescript +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class DataService { + private dataSubject = new Subject<string>(); + public data$ = this.dataSubject.asObservable(); + + setData(data: string) { + this.dataSubject.next(data); + } +} +``` + +In this example, a `DataService` is created that contains a `dataSubject` subject. The `data$` property is an observable that other components can subscribe to in order to receive the emitted values. The `setData` method is used to emit a value to the subject, which will then be received by any subscribed components. + +#### Handling user events + +Subjects can also be used to handle user events, such as button clicks or form submissions. This can be useful in situations where multiple components need to respond to the same event. + +```typescript +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class EventService { + private buttonClickSubject = new Subject<void>(); + public buttonClick$ = this.buttonClickSubject.asObservable(); + + buttonClicked() { + this.buttonClickSubject.next(); + } +} +``` + +In this example, an `EventService` is created that contains a `buttonClickSubject` subject. The `buttonClick$` property is an observable that other components can subscribe to in order to receive the emitted values. The `buttonClicked` method is used to emit a value to the subject, which will then be received by any subscribed components. + +In summary, subjects are a key concept in reactive programming with RXJS in Angular. They allow for both subscribing and emitting values, and can be used to handle data communication between components and services, as well as user events. By using subjects, developers can build more powerful and maintainable applications in Angular. + +## Best Practices for Reactive Programming in Angular with RXJS + +### Use of Pure Functions + +One of the core principles of reactive programming is the use of pure functions. These functions should take an input and return an output without causing any side effects. This makes it easier to reason about the behavior of the application and helps prevent unintended consequences. In Angular, you can use pure functions to transform data in Observables by using the map operator, for example. + +### Avoidance of Side Effects + +Side effects can make it difficult to reason about the behavior of an application. In reactive programming, side effects should be avoided as much as possible. This means that Observables should not cause any side effects when they are subscribed to. If a side effect is necessary, it should be isolated and contained to a specific part of the application. + +### Proper Use of Observables, Operators, and Subjects + +Proper use of Observables, Operators, and Subjects is essential for effective reactive programming with RXJS in Angular. Observables should be used to represent streams of data, and Operators should be used to transform and filter that data. Subjects should be used to create new Observables or to act as a bridge between different parts of the application. + +### Error Handling + +Error handling is critical in reactive programming to ensure the stability and reliability of the application. In Angular, you can use the catchError operator to handle errors and prevent them from propagating throughout the application. It is also important to properly handle errors in Subjects and to provide informative error messages to users. + +By following these best practices, you can write more effective and reliable code with reactive programming in Angular using RXJS. + +## Conclusion + +Reactive programming with RXJS in Angular is a powerful way to build applications that are responsive, scalable, and easy to maintain. Here are some key takeaways from this post: + +- Reactive programming is a programming paradigm that emphasizes the use of data streams and functional programming concepts to build responsive and scalable applications. +- RXJS is a library that provides powerful tools for implementing reactive programming in Angular. +- Key concepts in RXJS include Observables, Operators, and Subjects, which allow you to create and manipulate data streams in your application. +- Best practices for reactive programming in Angular include the use of pure functions, avoidance of side effects, proper use of Observables, Operators, and Subjects, and effective error handling. + +In summary, reactive programming with RXJS in Angular offers a number of benefits, including improved performance, scalability, and maintainability. By following best practices and using key concepts effectively, you can build applications that are responsive, reliable, and easy to maintain. + +Looking ahead, the future of reactive programming in Angular with RXJS looks bright. As Angular continues to evolve, we can expect to see even more powerful tools and features for building reactive applications. By staying up to date with the latest developments and best practices, you can continue to improve the quality and effectiveness of your code. diff --git a/mkdocs.yml b/mkdocs.yml index 24c29a5135f09987c453397c63253648ad9b10e9..10e11c515933ab085ed8440590874f09eb92617d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,8 @@ nav: - Accueil: index.md - Communication: communication.md - Navigation: navigation.md + - Getari: getari.md + - Reactive Programming: reactive-programming.md site_name: Portail Forge