Angular
Samuel eyre
CC BY-NC-SA samueleyre 2021
Concepts
Index
Ressources
COMPONENT
Une classe liée à du html et du css
@Component({
selector: 'app-un-nom',
templateUrl: './un-nom.component.html',
styleUrls: ['./un-nom.component.scss']
})
export class UnNomComponent implements OnInit {
constructor() {
}
ngOnInit() {
}
}
Le selector permet d'appeler le component dans du html avec : "<app-un-nom></app-un-nom> "
ngOnInit est appelé quand quand le DOM est chargé
MODULE
Une classe rattachée à des dépendances locales ou externes qui délimite un domaine de l'application de manière à créer des blocks le plus possible indépendants
@NgModule({
declarations: [
UnComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
CoreModule,
SharedModule,
],
exports: [
UnComponent,
],
})
export class AppModule { }
Les components sont déclarés dans "declarations" afin d'être compilés dans le module.
Les dépendances externes sont appelées dans "imports"
Pour rendre accessible des components dans les modules qui importent AppModule il faut les appeler dans "exports"
ROUTER
Lie les components avec les chemins de l'url
Cette balise est remplacée par le html chargé par le component.
<router-outlet></router-outlet>
Le Lazy Loading
Pour charger des modules dynamiquement, en fonction des chemins de l'url
const routes: Routes = [
{
path: 'direct', component: DirectComponent
},
{
path: 'sous',
loadChildren: () => import('./sous/sous.module').then(mod => mod.SousModule),
},
];
Le chemin '/direct' chargement rapidement car le component est déjà téléchargé par le navigateur.
Les chemins '/sous/**' chargement après téléchargement du module 'SousModule'
SERVICE
Un classe injectable qui sert à processer des données ou stocker des données réutilisables
On peut injecter des services dans des components, dans d'autres services ou tout autre classe angular, mais attention aux dépendances circulaires !
"providedIn" définit l'accessibilité de la classe. Si on met "root", elle sera injectable dans toute l'application.
@Injectable({
providedIn: 'root'
})
export class UnService {
constructor(
private autreService: AutreService,
) { }
}
OBSERVABLE
Un flux d’événements angular asynchrone auquel on peut s'inscrire
const observable$ = of(1, 2, 3);
observable$.subscribe((val) => {
console.log(val);
});
"of()" permet de créer un observable avec un flux de données : "1,2,3" ( utile pour cet exemple )
Subscribe() sert à observer ce qu'il se passe et récupérer les données
OBSERVABLE
Dans le cas d'une requête
const observable$ = this.httpClient.get('/api-path');
observable$.subscribe((val) => {
console.log(val);
});
Ici subscribe sert à exécuter la requête et récupérer la réponse.
PIPE ( opérateur RXJS )
Modifie "à la volé" les données dans un flux de données.
const observable$ = of(1, 2, 3);
observable$.pipe(map((val) => {
return val * 2;
})).subscribe((val) => {
console.log(val);
});
On modifie chaque donnée avec la fonction "map()"
Pour découvrir toutes les opérations possibles ( telle que "map()"), voir la doc de rxjs.
SUBJECT
Un Observable qui permet d'avoir plusieurs "observers" ( et donc plusieurs subscribe )
const subject = new Subject<number>();
subject.subscribe((val) => {
console.log('subject subscribe 1, val :',
val);
});
subject.subscribe((val) => {
console.log('subject subscribe 2, val :',
val);
});
const observable$ = of(1, 2, 3).pipe(
tap(val => {
console.log('source :', val);
subject.next(val);
})
).subscribe();
const observable$ = of(1, 2, 3).pipe(
tap(val => {
console.log('source :', val);
})
);
observable$.subscribe((val) => {
console.log('obs subscribe 1', val);
});
observable$.subscribe((val) => {
console.log('obs subscribe 2', val);
});
Différence entre l'utilisation de subjects (gauche) et d'observables ( droite )
On execute l'observable 1 seule fois
On execute l'observable 2 seule fois
source : 1
subject subscribe 1, val : 1
subject subscribe 2, val : 1
source : 2
subject subscribe 1, val : 2
subject subscribe 2, val : 2
source : 3
subject subscribe 1, val : 3
subject subscribe 2, val : 3
source : 1
obs subscribe 1 1
source : 2
obs subscribe 1 2
source : 3
obs subscribe 1 3
source : 1
obs subscribe 2 1
source : 2
obs subscribe 2 2
source : 3
obs subscribe 2 3
Affichage dans la console des exemples précédants.
l'Observable est exécuté 1 fois
l'Observable est exécuté 2 fois
Input / Ouput
On peut transférer et récupérer des données d'un component
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
})
export class ExampleComponent implements OnInit {
@Input() data: string;
@Output() dataEvent = new EventEmitter<string>();
ngOnInit(): void {
console.log('input : ', this.data);
}
emitValue(value: string) {
this.dataEvent.emit(value);
}
}
<app-example [data]="'value or variable'"
(dataEvent)="doSomething($event)">
</app-example>
La fonction 'doSomething()' sera appelé quand un événenement est émit.
Text
La donnée passé par la variable 'data' est récupéré pendant la construction du component.
Exemple en groupe
- o
Un flux d’événements angular asynchrone auquel on peut s'inscrire
11.
12.
13.
14.
15.
16.
17.
Objectifs
Découvrir les features et concepts du framework avec un example pratique sur une api existante.
Aller sur stackblitz
Copier en local
-
forker le stackblitz
-
connecter à un nouveau github
-
cloner en local
Module Core
Créer le module Core avec un service d'authentification qui permet de faire des appels à l'api pour se connecter, s'inscrire et appeler la route ping pour récupérer l'utilisateur connecté
Module Auth
- Créer le module "Auth"
- Créer une page de login avec une route dédiée
- Créer un formulaire de login en utilisation l'approche Reactive avec un FormGroup
- Connecter le formulaire à l'api via le service d'auth
Session
- Créer le service session qui permet de stocker en localstorage le token renvoyé lors du login
Dashboard
- Créer le module "dash"
- Créer une page d'accueil vers laquelle on est redirigé après login
Lazy loading
- Charger dynamiquement les modules Auth et Dash en créant les fichiers auth-routing.module.ts et dash-routing.module.ts pour gérer localement les routes
Guard
- créer un guard qui faire une requête à la route ping ( via authService ) et autoriser ou non l'accès en fonction du statut de la réponse de la requête
- assigner ce guard à la route '/dash'
Intercepteur
- créer un intercepteur qui va ajouter le token ( jwt ) stocké dans la session à chaque requête sous la forme :
Authorization: `Bearer ${token}`
- assigner ce guard à la route '/dash'
Inscription
- créer une page 'signup'
- créer un formulaire pour l'inscription avec les champs : 'first_name', 'last_name', 'email', 'password'
- mettre de la validation sur les champs email et mot de passe ( + de 6 caractères )
Redirection
- rediriger l'origine vers signin
- faire une page 404 pour les autres cas
Utilisateur connecté
- récupérer l'utilisateur connecté via le guard quand le statut est 200 et le stocker dans auth.service.ts
Navbar
- créer une navbar Material dans app.component.html
- récupérer l'utilisateur connecté pour savoir si l'utilisateur est connecté ou non
- ajouter toutes les routes dans la navbar en prenant en compte si l'utilisateur est connecté ou non
Déconnexion
- ajouter un bouton déconnexion qui fait retourner l'utilisateur vers la page de login
- au moment de la déconnexion vider le localstorage et réinitialiser service auth
Matching
- récupérer les utilisateurs qui matchent avec le profil connecté à l'aide d'un service 'match'
- afficher les données des matchs ( nom, prénom, tags d'apprentissage ) dans des cartes
Page profil
- créer une page profil avec un formulaire ( 'first_name', 'last_name', 'tags' ), utiliser un select multi Material
- connecter le formulaire à l'api en créant un service 'profile'
- récupérer les tags pour le select avec l'api dédié à un auto-complete en créant un service 'tag'
Refacto du formulaire
- créer un module "shared"
- refactorer les formulaires en mettant en commun les champs : "prenom", "nom", "email", "mot de passe" avec des components dédiés en passant le formGroup en Input des components enfants, dans le module "shared"
Admin
- créer un module admin et le charger dynamiquement (lazy loading) sur la route 'admin'
- créer une page admin accessible uniquement en étant connecté
- sur la route 'admin' passer en data : { admin : true }
- mettre à jour le guard pour permettre l'accès aux routes où est spécifié la data { admin :true } uniquement si l'utilisateur a le role 'ROLE_ADMIN' ( transmis via l'api )
API
login_check (post) : { email, password }
=> { token }
signup (post) : { email, password, first_name, last_name }
=> User
Connexion
Inscription
URL : https://api-teaching.wecolearn.com/api/
Vérifier la connexion et récupérer les données utilisateurs
ping (get) : => User
tag/find (get) : => Tag[]
user/matchs (post) : { max? } => User[]
Récupérer des tags ( pour un auto-complete )
Récupérer les profils qui matchent
profile (patch) : { first_name, last_name, tags } => User
Modifier les données du profil
admin/tags (get) : => Tag[]
Récupérer tous les tags ( admin )
Angular
By samuel eyre
Angular
- 191