From 9cffdc89d90acb6c91a7bcbfbc24d7f05538e44a Mon Sep 17 00:00:00 2001
From: Oumaima-Lg <141629272+Oumaima-Lg@users.noreply.github.com>
Date: Sun, 28 Sep 2025 21:12:47 +0100
Subject: [PATCH 1/3] feat: add ng-content and handle css style
---
.../student-card/student-card.component.ts | 18 ++++++++--------
.../teacher-card/teacher-card.component.ts | 21 ++++++++-----------
.../src/app/ui/card/card.component.ts | 10 ++-------
apps/angular/1-projection/src/styles.scss | 14 +++++++++++++
4 files changed, 34 insertions(+), 29 deletions(-)
diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
index bdfa4abd4..f07a329cf 100644
--- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
@@ -1,3 +1,4 @@
+import { NgOptimizedImage } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
@@ -15,16 +16,15 @@ import { CardComponent } from '../../ui/card/card.component';
+ customClass="bg-light-green">
+
+
`,
- styles: [
- `
- ::ng-deep .bg-light-green {
- background-color: rgba(0, 250, 0, 0.1);
- }
- `,
- ],
- imports: [CardComponent],
+ imports: [CardComponent, NgOptimizedImage],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StudentCardComponent implements OnInit {
diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
index adf0ad3c1..b4f3adf48 100644
--- a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
@@ -1,3 +1,4 @@
+import { NgOptimizedImage } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
import { FakeHttpService } from '../../data-access/fake-http.service';
import { TeacherStore } from '../../data-access/teacher.store';
@@ -7,19 +8,15 @@ import { CardComponent } from '../../ui/card/card.component';
@Component({
selector: 'app-teacher-card',
template: `
-
+
+
+
`,
- styles: [
- `
- ::ng-deep .bg-light-red {
- background-color: rgba(250, 0, 0, 0.1);
- }
- `,
- ],
- imports: [CardComponent],
+ imports: [CardComponent, NgOptimizedImage],
})
export class TeacherCardComponent implements OnInit {
private http = inject(FakeHttpService);
diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts
index 1a6c3648c..e807e8e21 100644
--- a/apps/angular/1-projection/src/app/ui/card/card.component.ts
+++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts
@@ -1,4 +1,3 @@
-import { NgOptimizedImage } from '@angular/common';
import { Component, inject, input } from '@angular/core';
import { randStudent, randTeacher } from '../../data-access/fake-http.service';
import { StudentStore } from '../../data-access/student.store';
@@ -12,12 +11,7 @@ import { ListItemComponent } from '../list-item/list-item.component';
- @if (type() === CardType.TEACHER) {
-
![]()
- }
- @if (type() === CardType.STUDENT) {
-
![]()
- }
+
@for (item of list(); track item) {
@@ -35,7 +29,7 @@ import { ListItemComponent } from '../list-item/list-item.component';
`,
- imports: [ListItemComponent, NgOptimizedImage],
+ imports: [ListItemComponent],
})
export class CardComponent {
private teacherStore = inject(TeacherStore);
diff --git a/apps/angular/1-projection/src/styles.scss b/apps/angular/1-projection/src/styles.scss
index b5c61c956..1e7a33b90 100644
--- a/apps/angular/1-projection/src/styles.scss
+++ b/apps/angular/1-projection/src/styles.scss
@@ -1,3 +1,17 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+
+
+.bg-light-green {
+ background-color: rgba(0, 250, 0, 0.1);
+}
+
+.bg-light-red {
+ background-color: rgba(250, 0, 0, 0.1);
+}
+
+.bg-light-blue {
+ background-color: rgba(0, 0, 250, 0.1);
+}
\ No newline at end of file
From f52f48d78b5daf199b831054f528f9e8eb7970de Mon Sep 17 00:00:00 2001
From: Oumaima-Lg <141629272+Oumaima-Lg@users.noreply.github.com>
Date: Sun, 28 Sep 2025 21:47:38 +0100
Subject: [PATCH 2/3] feat: add ng-content2
---
.../student-card/student-card.component.ts | 21 +++++++++++++---
.../teacher-card/teacher-card.component.ts | 21 +++++++++++++---
.../src/app/ui/card/card.component.ts | 25 ++-----------------
3 files changed, 36 insertions(+), 31 deletions(-)
diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
index f07a329cf..22474034b 100644
--- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
@@ -5,7 +5,10 @@ import {
inject,
OnInit,
} from '@angular/core';
-import { FakeHttpService } from '../../data-access/fake-http.service';
+import {
+ FakeHttpService,
+ randStudent,
+} from '../../data-access/fake-http.service';
import { StudentStore } from '../../data-access/student.store';
import { CardType } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';
@@ -22,6 +25,12 @@ import { CardComponent } from '../../ui/card/card.component';
ngSrc="assets/img/student.webp"
width="200"
height="200" />
+
`,
imports: [CardComponent, NgOptimizedImage],
@@ -29,12 +38,16 @@ import { CardComponent } from '../../ui/card/card.component';
})
export class StudentCardComponent implements OnInit {
private http = inject(FakeHttpService);
- private store = inject(StudentStore);
+ private studentStore = inject(StudentStore);
- students = this.store.students;
+ students = this.studentStore.students;
cardType = CardType.STUDENT;
ngOnInit(): void {
- this.http.fetchStudents$.subscribe((s) => this.store.addAll(s));
+ this.http.fetchStudents$.subscribe((s) => this.studentStore.addAll(s));
+ }
+
+ addStudent() {
+ this.studentStore.addOne(randStudent());
}
}
diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
index b4f3adf48..36757a4a4 100644
--- a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
@@ -1,6 +1,9 @@
import { NgOptimizedImage } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
-import { FakeHttpService } from '../../data-access/fake-http.service';
+import {
+ FakeHttpService,
+ randTeacher,
+} from '../../data-access/fake-http.service';
import { TeacherStore } from '../../data-access/teacher.store';
import { CardType } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';
@@ -14,18 +17,28 @@ import { CardComponent } from '../../ui/card/card.component';
ngSrc="assets/img/teacher.png"
width="200"
height="200" />
+
`,
imports: [CardComponent, NgOptimizedImage],
})
export class TeacherCardComponent implements OnInit {
private http = inject(FakeHttpService);
- private store = inject(TeacherStore);
+ private studentStore = inject(TeacherStore);
- teachers = this.store.teachers;
+ teachers = this.studentStore.teachers;
cardType = CardType.TEACHER;
ngOnInit(): void {
- this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t));
+ this.http.fetchTeachers$.subscribe((t) => this.studentStore.addAll(t));
+ }
+
+ addTeacher() {
+ this.studentStore.addOne(randTeacher());
}
}
diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts
index e807e8e21..2ebc9b711 100644
--- a/apps/angular/1-projection/src/app/ui/card/card.component.ts
+++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts
@@ -1,7 +1,4 @@
-import { Component, inject, input } from '@angular/core';
-import { randStudent, randTeacher } from '../../data-access/fake-http.service';
-import { StudentStore } from '../../data-access/student.store';
-import { TeacherStore } from '../../data-access/teacher.store';
+import { Component, input } from '@angular/core';
import { CardType } from '../../model/card.model';
import { ListItemComponent } from '../list-item/list-item.component';
@@ -22,31 +19,13 @@ import { ListItemComponent } from '../list-item/list-item.component';
}
-
+
`,
imports: [ListItemComponent],
})
export class CardComponent {
- private teacherStore = inject(TeacherStore);
- private studentStore = inject(StudentStore);
-
readonly list = input(null);
readonly type = input.required();
readonly customClass = input('');
-
- CardType = CardType;
-
- addNewItem() {
- const type = this.type();
- if (type === CardType.TEACHER) {
- this.teacherStore.addOne(randTeacher());
- } else if (type === CardType.STUDENT) {
- this.studentStore.addOne(randStudent());
- }
- }
}
From ece4b1170646119dcdcea45dd6b1b0e531be701e Mon Sep 17 00:00:00 2001
From: Oumaima-Lg <141629272+Oumaima-Lg@users.noreply.github.com>
Date: Mon, 29 Sep 2025 12:49:37 +0100
Subject: [PATCH 3/3] fix: handle CSS styling
---
.../city-card/city-card.component.ts | 65 +++++++++++++++++--
.../student-card/student-card.component.ts | 47 +++++++++-----
.../teacher-card/teacher-card.component.ts | 49 +++++++++-----
.../src/app/data-access/city.store.ts | 2 +-
.../src/app/ui/card/card.component.ts | 29 +++++----
.../app/ui/list-item/list-item.component.ts | 22 ++-----
apps/angular/1-projection/src/styles.scss | 18 ++---
7 files changed, 157 insertions(+), 75 deletions(-)
diff --git a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts
index 8895c8c84..a5e141abd 100644
--- a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts
@@ -1,9 +1,66 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { NgOptimizedImage } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ OnInit,
+ ViewEncapsulation,
+} from '@angular/core';
+import { CityStore } from '../../data-access/city.store';
+import {
+ FakeHttpService,
+ randomCity,
+} from '../../data-access/fake-http.service';
+import { CardComponent } from '../../ui/card/card.component';
+import { ListItemComponent } from '../../ui/list-item/list-item.component';
@Component({
selector: 'app-city-card',
- template: 'TODO City',
- imports: [],
+ template: `
+
+
+
+
+
+
+
+
+
+ `,
+ styles: [
+ `
+ .bg-light-blue {
+ background-color: rgba(0, 0, 250, 0.1);
+ }
+ `,
+ ],
+ imports: [CardComponent, ListItemComponent, NgOptimizedImage],
changeDetection: ChangeDetectionStrategy.OnPush,
+ encapsulation: ViewEncapsulation.None,
})
-export class CityCardComponent {}
+export class CityCardComponent implements OnInit {
+ private http = inject(FakeHttpService);
+ private store = inject(CityStore);
+
+ cities = this.store.cities;
+
+ ngOnInit(): void {
+ this.http.fetchCities$.subscribe((c) => this.store.addAll(c));
+ }
+
+ addNewCity() {
+ this.store.addOne(randomCity());
+ }
+
+ deleteCity(id: number) {
+ this.store.deleteOne(id);
+ }
+}
diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
index 22474034b..38228530a 100644
--- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts
@@ -4,50 +4,67 @@ import {
Component,
inject,
OnInit,
+ ViewEncapsulation,
} from '@angular/core';
import {
FakeHttpService,
randStudent,
} from '../../data-access/fake-http.service';
import { StudentStore } from '../../data-access/student.store';
-import { CardType } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';
+import { ListItemComponent } from '../../ui/list-item/list-item.component';
@Component({
selector: 'app-student-card',
template: `
-
+
+
+
+
+
+
`,
- imports: [CardComponent, NgOptimizedImage],
+ styles: [
+ `
+ .bg-light-green {
+ background-color: rgba(0, 250, 0, 0.1);
+ }
+ `,
+ ],
+ imports: [CardComponent, ListItemComponent, NgOptimizedImage],
changeDetection: ChangeDetectionStrategy.OnPush,
+ encapsulation: ViewEncapsulation.None,
})
export class StudentCardComponent implements OnInit {
private http = inject(FakeHttpService);
- private studentStore = inject(StudentStore);
+ private store = inject(StudentStore);
- students = this.studentStore.students;
- cardType = CardType.STUDENT;
+ students = this.store.students;
ngOnInit(): void {
- this.http.fetchStudents$.subscribe((s) => this.studentStore.addAll(s));
+ this.http.fetchStudents$.subscribe((s) => this.store.addAll(s));
+ }
+
+ addNewStudent() {
+ this.store.addOne(randStudent());
}
- addStudent() {
- this.studentStore.addOne(randStudent());
+ deleteStudent(id: number) {
+ this.store.deleteOne(id);
}
}
diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
index 36757a4a4..2023bc7ed 100644
--- a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
+++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts
@@ -1,44 +1,59 @@
import { NgOptimizedImage } from '@angular/common';
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
import {
FakeHttpService,
randTeacher,
} from '../../data-access/fake-http.service';
import { TeacherStore } from '../../data-access/teacher.store';
-import { CardType } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';
+import { ListItemComponent } from '../../ui/list-item/list-item.component';
@Component({
selector: 'app-teacher-card',
template: `
-
-
+
+
+
+
+
+
+
`,
- imports: [CardComponent, NgOptimizedImage],
+ styles: [
+ `
+ .bg-light-red {
+ background-color: rgba(250, 0, 0, 0.1);
+ }
+ `,
+ ],
+ imports: [CardComponent, ListItemComponent, NgOptimizedImage],
+ encapsulation: ViewEncapsulation.None,
})
export class TeacherCardComponent implements OnInit {
private http = inject(FakeHttpService);
- private studentStore = inject(TeacherStore);
+ private store = inject(TeacherStore);
- teachers = this.studentStore.teachers;
- cardType = CardType.TEACHER;
+ teachers = this.store.teachers;
ngOnInit(): void {
- this.http.fetchTeachers$.subscribe((t) => this.studentStore.addAll(t));
+ this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t));
+ }
+
+ addNewTeacher() {
+ this.store.addOne(randTeacher());
}
- addTeacher() {
- this.studentStore.addOne(randTeacher());
+ deleteTeacher(id: number) {
+ this.store.deleteOne(id);
}
}
diff --git a/apps/angular/1-projection/src/app/data-access/city.store.ts b/apps/angular/1-projection/src/app/data-access/city.store.ts
index a8b523569..9fbcb346b 100644
--- a/apps/angular/1-projection/src/app/data-access/city.store.ts
+++ b/apps/angular/1-projection/src/app/data-access/city.store.ts
@@ -5,7 +5,7 @@ import { City } from '../model/city.model';
providedIn: 'root',
})
export class CityStore {
- private cities = signal([]);
+ public cities = signal([]);
addAll(cities: City[]) {
this.cities.set(cities);
diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts
index 2ebc9b711..4ed1cdffd 100644
--- a/apps/angular/1-projection/src/app/ui/card/card.component.ts
+++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts
@@ -1,6 +1,5 @@
-import { Component, input } from '@angular/core';
-import { CardType } from '../../model/card.model';
-import { ListItemComponent } from '../list-item/list-item.component';
+import { NgTemplateOutlet } from '@angular/common';
+import { Component, contentChild, input, TemplateRef } from '@angular/core';
@Component({
selector: 'app-card',
@@ -8,24 +7,28 @@ import { ListItemComponent } from '../list-item/list-item.component';
-
+
- @for (item of list(); track item) {
-
+ @for (item of list(); track item.id) {
+
}
-
+
`,
- imports: [ListItemComponent],
+
+ imports: [NgTemplateOutlet],
})
export class CardComponent {
- readonly list = input(null);
- readonly type = input.required();
+ readonly list = input([]);
readonly customClass = input('');
+ readonly trackByFn = input<(item: any) => any>((item) => item.id);
+
+ readonly itemTemplate = contentChild.required>('listItem');
}
diff --git a/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts b/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts
index 5d504f372..7044f2caf 100644
--- a/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts
+++ b/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts
@@ -1,19 +1,16 @@
import {
ChangeDetectionStrategy,
Component,
- inject,
input,
+ output,
} from '@angular/core';
-import { StudentStore } from '../../data-access/student.store';
-import { TeacherStore } from '../../data-access/teacher.store';
-import { CardType } from '../../model/card.model';
@Component({
selector: 'app-list-item',
template: `
{{ name() }}
-
@@ -21,19 +18,12 @@ import { CardType } from '../../model/card.model';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ListItemComponent {
- private teacherStore = inject(TeacherStore);
- private studentStore = inject(StudentStore);
-
readonly id = input.required();
readonly name = input.required();
- readonly type = input.required();
- delete(id: number) {
- const type = this.type();
- if (type === CardType.TEACHER) {
- this.teacherStore.deleteOne(id);
- } else if (type === CardType.STUDENT) {
- this.studentStore.deleteOne(id);
- }
+ readonly delete = output();
+
+ onDelete() {
+ this.delete.emit(this.id());
}
}
diff --git a/apps/angular/1-projection/src/styles.scss b/apps/angular/1-projection/src/styles.scss
index 1e7a33b90..a2e79cfde 100644
--- a/apps/angular/1-projection/src/styles.scss
+++ b/apps/angular/1-projection/src/styles.scss
@@ -4,14 +4,14 @@
-.bg-light-green {
- background-color: rgba(0, 250, 0, 0.1);
-}
+// .bg-light-green {
+// background-color: rgba(0, 250, 0, 0.1);
+// }
-.bg-light-red {
- background-color: rgba(250, 0, 0, 0.1);
-}
+// .bg-light-red {
+// background-color: rgba(250, 0, 0, 0.1);
+// }
-.bg-light-blue {
- background-color: rgba(0, 0, 250, 0.1);
-}
\ No newline at end of file
+// .bg-light-blue {
+// background-color: rgba(0, 0, 250, 0.1);
+// }
\ No newline at end of file