From b52f4b400e24e96583e163b8f1c67c6feea29699 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 4 Nov 2024 13:35:49 +0300 Subject: [PATCH] feat: resolve projection of Answer:1 --- .../city-card/city-card.component.ts | 47 +++++++++-- .../student-card/student-card.component.ts | 40 +++++++--- .../teacher-card/teacher-card.component.ts | 47 ++++++++--- .../src/app/data-access/city.store.ts | 4 +- .../src/app/ui/card/card.component.ts | 77 ++++++++----------- .../list-item/list-item-template.directive.ts | 9 +++ .../app/ui/list-item/list-item.component.ts | 37 +++------ 7 files changed, 159 insertions(+), 102 deletions(-) create mode 100644 apps/angular/1-projection/src/app/ui/list-item/list-item-template.directive.ts 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 30c8f88ec..c1c6693a3 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,13 +1,50 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { CityStore } from '../../data-access/city.store'; +import { + FakeHttpService, + randomCity, +} from '../../data-access/fake-http.service'; +import { City } from '../../model/city.model'; +import { CardComponent } from '../../ui/card/card.component'; +import { ListItemTemplateDirective } from '../../ui/list-item/list-item-template.directive'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-city-card', - template: 'TODO City', + template: ` + + student + + + + {{ city.name }} + + + + `, standalone: true, - imports: [], + imports: [CardComponent, ListItemTemplateDirective, ListItemComponent], }) export class CityCardComponent implements OnInit { - constructor() {} + cities: Signal = toSignal(this.store.cities$, { + initialValue: [], + }); + + constructor( + private http: FakeHttpService, + private store: CityStore, + ) {} + + ngOnInit(): void { + this.http.fetchCities$.subscribe((s) => this.store.addAll(s)); + } + + addCity() { + this.store.addOne(randomCity()); + } - ngOnInit(): void {} + 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 441cda189..d4909b66b 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,31 +1,41 @@ import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { + FakeHttpService, + randStudent, +} from '../../data-access/fake-http.service'; import { StudentStore } from '../../data-access/student.store'; -import { CardType } from '../../model/card.model'; -import { Student } from '../../model/student.model'; import { CardComponent } from '../../ui/card/card.component'; +import { ListItemTemplateDirective } from '../../ui/list-item/list-item-template.directive'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-student-card', template: ` - + + student + + + + {{ student.firstName }} + + + `, standalone: true, styles: [ ` - ::ng-deep .bg-light-green { + .bg-light-green { background-color: rgba(0, 250, 0, 0.1); } `, ], - imports: [CardComponent], + imports: [CardComponent, ListItemComponent, ListItemTemplateDirective], }) export class StudentCardComponent implements OnInit { - students: Student[] = []; - cardType = CardType.STUDENT; + students = toSignal(this.store.students$, { + initialValue: [], + }); constructor( private http: FakeHttpService, @@ -34,7 +44,13 @@ export class StudentCardComponent implements OnInit { ngOnInit(): void { this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); + } + + addStudent() { + this.store.addOne(randStudent()); + } - this.store.students$.subscribe((s) => (this.students = s)); + 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 995cb7c2f..debbf3c66 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,31 +1,48 @@ -import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { + ChangeDetectionStrategy, + Component, + OnInit, + Signal, +} from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { + FakeHttpService, + randTeacher, +} from '../../data-access/fake-http.service'; import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; import { Teacher } from '../../model/teacher.model'; import { CardComponent } from '../../ui/card/card.component'; +import { ListItemTemplateDirective } from '../../ui/list-item/list-item-template.directive'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-teacher-card', template: ` - + + teacher + + + + {{ teacher.firstName }} + + + `, styles: [ ` - ::ng-deep .bg-light-red { + .bg-light-red { background-color: rgba(250, 0, 0, 0.1); } `, ], standalone: true, - imports: [CardComponent], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CardComponent, ListItemComponent, ListItemTemplateDirective], }) export class TeacherCardComponent implements OnInit { - teachers: Teacher[] = []; - cardType = CardType.TEACHER; + teachers: Signal = toSignal(this.store.teachers$, { + initialValue: [], + }); constructor( private http: FakeHttpService, @@ -34,7 +51,13 @@ export class TeacherCardComponent implements OnInit { ngOnInit(): void { this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t)); + } + + addTeacher() { + this.store.addOne(randTeacher()); + } - this.store.teachers$.subscribe((t) => (this.teachers = t)); + 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 711dad1d7..c2b6bd1db 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 @@ -13,8 +13,8 @@ export class CityStore { this.cities.next(cities); } - addOne(student: City) { - this.cities.next([...this.cities.value, student]); + addOne(city: City) { + this.cities.next([...this.cities.value, city]); } deleteOne(id: number) { 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 f06c9ae00..c9879d81a 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,61 +1,48 @@ -import { NgFor, NgIf } from '@angular/common'; -import { Component, 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 { NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + contentChild, + input, + output, +} from '@angular/core'; +import { ListItemTemplateDirective } from '../list-item/list-item-template.directive'; import { ListItemComponent } from '../list-item/list-item.component'; @Component({ selector: 'app-card', template: ` -
- - + -
- -
+
+ @for (item of list(); track item) { + + } +
- -
+ `, standalone: true, - imports: [NgIf, NgFor, ListItemComponent], + imports: [ListItemComponent, NgTemplateOutlet], + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'flex w-fit flex-col gap-3 rounded-md border-2 border-black p-4', + }, }) -export class CardComponent { - @Input() list: any[] | null = null; - @Input() type!: CardType; - @Input() customClass = ''; +export class CardComponent { + list = input([]); - CardType = CardType; + itemTemplate = contentChild(ListItemTemplateDirective); - constructor( - private teacherStore: TeacherStore, - private studentStore: StudentStore, - ) {} + add = output(); addNewItem() { - if (this.type === CardType.TEACHER) { - this.teacherStore.addOne(randTeacher()); - } else if (this.type === CardType.STUDENT) { - this.studentStore.addOne(randStudent()); - } + this.add.emit(); } } diff --git a/apps/angular/1-projection/src/app/ui/list-item/list-item-template.directive.ts b/apps/angular/1-projection/src/app/ui/list-item/list-item-template.directive.ts new file mode 100644 index 000000000..95a002400 --- /dev/null +++ b/apps/angular/1-projection/src/app/ui/list-item/list-item-template.directive.ts @@ -0,0 +1,9 @@ +import { Directive, TemplateRef } from '@angular/core'; + +@Directive({ + selector: '[appListItemTemplate]', + standalone: true, +}) +export class ListItemTemplateDirective { + constructor(public templateRef: TemplateRef) {} +} 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 c0f9cff7f..d7e371cf3 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,35 +1,20 @@ -import { Component, 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 }} - -
+ + + `, standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'border-grey-300 flex justify-between border px-2 py-1', + }, }) export class ListItemComponent { - @Input() id!: number; - @Input() name!: string; - @Input() type!: CardType; - - constructor( - private teacherStore: TeacherStore, - private studentStore: StudentStore, - ) {} - - delete(id: number) { - if (this.type === CardType.TEACHER) { - this.teacherStore.deleteOne(id); - } else if (this.type === CardType.STUDENT) { - this.studentStore.deleteOne(id); - } - } + deleteItem = output(); }