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