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..a4ea5e3ee 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,57 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { NgOptimizedImage } from '@angular/common'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { CityStore } from '../../data-access/city.store'; +import { + FakeHttpService, + randomCity, +} from '../../data-access/fake-http.service'; +import { CardComponent, ItemRefDirective } from '../../ui/card/card.component'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-city-card', - template: 'TODO City', - imports: [], + template: ` + + + + + {{ item.name }} + + + + `, + styles: [ + ` + app-card { + background-color: rgba(0, 0, 250, 0.1); + } + `, + ], + host: { + class: 'flex justify-center p-4', + }, + imports: [ + CardComponent, + ListItemComponent, + ItemRefDirective, + NgOptimizedImage, + ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CityCardComponent {} +export class CityCardComponent { + private http = inject(FakeHttpService); + private store = inject(CityStore); + cities = this.store.cities; + + ngOnInit(): void { + this.http.fetchCities$.subscribe((c) => this.store.addAll(c)); + } + + deleteCity(id: number) { + this.store.deleteOne(id); + } + + addCity() { + this.store.addOne(randomCity()); + } +} 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..75381d07d 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,40 +1,62 @@ +import { NgOptimizedImage } from '@angular/common'; import { ChangeDetectionStrategy, Component, 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'; +import { CardComponent, ItemRefDirective } from '../../ui/card/card.component'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-student-card', template: ` - + + + + + {{ item.firstName }} + + + `, styles: [ ` - ::ng-deep .bg-light-green { + app-card { background-color: rgba(0, 250, 0, 0.1); } `, ], - imports: [CardComponent], + host: { + class: 'flex justify-center p-4', + }, + imports: [ + CardComponent, + ListItemComponent, + ItemRefDirective, + NgOptimizedImage, + ], changeDetection: ChangeDetectionStrategy.OnPush, }) export class StudentCardComponent implements OnInit { private http = inject(FakeHttpService); private store = inject(StudentStore); - students = this.store.students; - cardType = CardType.STUDENT; ngOnInit(): void { this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); } + + deleteStudent(id: number) { + this.store.deleteOne(id); + } + + addStudent() { + this.store.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 adf0ad3c1..6378f73fa 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,34 +1,55 @@ +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'; +import { CardComponent, ItemRefDirective } from '../../ui/card/card.component'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-teacher-card', template: ` - + + + + + {{ item.firstName }} + + + `, styles: [ ` - ::ng-deep .bg-light-red { + app-card { background-color: rgba(250, 0, 0, 0.1); } `, ], - imports: [CardComponent], + host: { + class: 'flex justify-center p-4', + }, + imports: [ + CardComponent, + ListItemComponent, + NgOptimizedImage, + ItemRefDirective, + ], }) export class TeacherCardComponent implements OnInit { private http = inject(FakeHttpService); private store = inject(TeacherStore); teachers = this.store.teachers; - cardType = CardType.TEACHER; ngOnInit(): void { this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t)); } + addTeacher() { + this.store.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..6d270404f 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([]); + 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 1a6c3648c..254ffb0ef 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,58 +1,48 @@ -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'; -import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; -import { ListItemComponent } from '../list-item/list-item.component'; +import { NgTemplateOutlet } from '@angular/common'; +import { + Component, + ContentChild, + Directive, + input, + output, + TemplateRef, +} from '@angular/core'; + +@Directive({ + selector: '[itemRef]', + standalone: true, +}) +export class ItemRefDirective {} @Component({ selector: 'app-card', template: ` -
- @if (type() === CardType.TEACHER) { - + +
+ @for (item of list(); track item.id) { + } - @if (type() === CardType.STUDENT) { - - } - -
- @for (item of list(); track item) { - - } -
- - -
+ + `, - imports: [ListItemComponent, NgOptimizedImage], + host: { + class: 'flex w-fit flex-col gap-3 rounded-md border-2 border-black p-4', + }, + imports: [NgTemplateOutlet], }) export class CardComponent { - private teacherStore = inject(TeacherStore); - private studentStore = inject(StudentStore); - + addNewItem = output(); 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()); - } - } + // [For My Ref] we can leverage on ng-content and template to reduce duplication and better code managment with reusability without changing much + // Using ContentChild to get the template reference from projected content read as TemplateRef without it doesnt give TemplateRef + @ContentChild(ItemRefDirective, { read: TemplateRef }) itemRef!: TemplateRef<{ + $implicit: any; + }>; } 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..2ac97eedb 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,39 +1,18 @@ -import { - ChangeDetectionStrategy, - Component, - inject, - input, -} from '@angular/core'; -import { StudentStore } from '../../data-access/student.store'; -import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; +import { ChangeDetectionStrategy, Component, output } from '@angular/core'; @Component({ selector: 'app-list-item', template: ` -
- {{ name() }} - -
+ + `, + host: { + class: 'border-grey-300 flex justify-between border px-2 py-1', + }, 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); - } - } + onDelete = output(); }