From 8dd636803a0ff50dd3d41fa2a2dd9e33b8505b07 Mon Sep 17 00:00:00 2001 From: Paramesh555 Date: Mon, 30 Jun 2025 21:33:41 +0530 Subject: [PATCH 1/2] feat(city): manually added city component --- .../city-card/city-card.component.ts | 34 ++++++++++++++++--- .../src/app/data-access/city.store.ts | 2 +- .../src/app/ui/card/card.component.ts | 30 +++++++++++++--- .../app/ui/list-item/list-item.component.ts | 4 +++ apps/angular/1-projection/tsconfig.json | 3 +- 5 files changed, 62 insertions(+), 11 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..e093d0674 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,35 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + OnInit, + inject, +} from '@angular/core'; +import { CityStore } from '../../data-access/city.store'; +import { FakeHttpService } from '../../data-access/fake-http.service'; +import { CardType } from '../../model/card.model'; +import { CardComponent } from '../../ui/card/card.component'; @Component({ selector: 'app-city-card', - template: 'TODO City', - imports: [], + template: ` + + `, + imports: [CardComponent], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CityCardComponent {} +export class CityCardComponent implements OnInit { + private http = inject(FakeHttpService); + private store = inject(CityStore); + + cities = this.store.cities; + cardType = CardType.CITY; + + ngOnInit(): void { + this.http.fetchCities$.subscribe((t) => { + this.store.addAll(t); + }); + } +} 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 1a6c3648c..1c3c28081 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,11 @@ import { NgOptimizedImage } from '@angular/common'; import { Component, inject, input } from '@angular/core'; -import { randStudent, randTeacher } from '../../data-access/fake-http.service'; +import { CityStore } from '../../data-access/city.store'; +import { + randStudent, + randTeacher, + randomCity, +} 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'; @@ -18,13 +23,25 @@ import { ListItemComponent } from '../list-item/list-item.component'; @if (type() === CardType.STUDENT) { } + @if (type() === CardType.CITY) { + + }
@for (item of list(); track item) { - + @if (type() === CardType.TEACHER || type() === CardType.STUDENT) { + + } + + @if (type() === CardType.CITY) { + + } }
@@ -40,6 +57,7 @@ import { ListItemComponent } from '../list-item/list-item.component'; export class CardComponent { private teacherStore = inject(TeacherStore); private studentStore = inject(StudentStore); + private cityStore = inject(CityStore); readonly list = input(null); readonly type = input.required(); @@ -53,6 +71,8 @@ export class CardComponent { this.teacherStore.addOne(randTeacher()); } else if (type === CardType.STUDENT) { this.studentStore.addOne(randStudent()); + } else if (type === CardType.CITY) { + this.cityStore.addOne(randomCity()); } } } 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..519a71e9e 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 @@ -4,6 +4,7 @@ import { inject, input, } from '@angular/core'; +import { CityStore } from '../../data-access/city.store'; import { StudentStore } from '../../data-access/student.store'; import { TeacherStore } from '../../data-access/teacher.store'; import { CardType } from '../../model/card.model'; @@ -23,6 +24,7 @@ import { CardType } from '../../model/card.model'; export class ListItemComponent { private teacherStore = inject(TeacherStore); private studentStore = inject(StudentStore); + private cityStore = inject(CityStore); readonly id = input.required(); readonly name = input.required(); @@ -34,6 +36,8 @@ export class ListItemComponent { this.teacherStore.deleteOne(id); } else if (type === CardType.STUDENT) { this.studentStore.deleteOne(id); + } else if (type === CardType.CITY) { + this.cityStore.deleteOne(id); } } } diff --git a/apps/angular/1-projection/tsconfig.json b/apps/angular/1-projection/tsconfig.json index 52eb4f718..0358ec445 100644 --- a/apps/angular/1-projection/tsconfig.json +++ b/apps/angular/1-projection/tsconfig.json @@ -20,7 +20,8 @@ "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "importHelpers": false }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, From f450e418d9de2cefb92ac844147e4e196994bcee Mon Sep 17 00:00:00 2001 From: Paramesh555 Date: Tue, 1 Jul 2025 23:00:44 +0530 Subject: [PATCH 2/2] feat: make card component independent using ng-template --- .../city-card/city-card.component.ts | 31 ++++++-- .../student-card/student-card.component.ts | 30 ++++++-- .../teacher-card/teacher-card.component.ts | 38 ++++++++-- .../src/app/ui/card/card.component.ts | 73 +++++-------------- .../app/ui/list-item/list-item.component.ts | 25 +------ 5 files changed, 101 insertions(+), 96 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 e093d0674..774b07130 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 @@ -5,19 +5,27 @@ import { inject, } from '@angular/core'; import { CityStore } from '../../data-access/city.store'; -import { FakeHttpService } from '../../data-access/fake-http.service'; -import { CardType } from '../../model/card.model'; +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: ` - + + + + + + `, - imports: [CardComponent], + imports: [CardComponent, ListItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, }) export class CityCardComponent implements OnInit { @@ -25,11 +33,18 @@ export class CityCardComponent implements OnInit { private store = inject(CityStore); cities = this.store.cities; - cardType = CardType.CITY; ngOnInit(): void { this.http.fetchCities$.subscribe((t) => { this.store.addAll(t); }); } + + addCity() { + 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 bdfa4abd4..432bdbc1f 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,18 +4,29 @@ 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'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-student-card', template: ` + customClass="bg-light-green" + (add)="addStudent()"> + + + + + `, styles: [ ` @@ -24,7 +35,7 @@ import { CardComponent } from '../../ui/card/card.component'; } `, ], - imports: [CardComponent], + imports: [CardComponent, ListItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, }) export class StudentCardComponent implements OnInit { @@ -32,9 +43,16 @@ export class StudentCardComponent implements OnInit { private store = inject(StudentStore); students = this.store.students; - cardType = CardType.STUDENT; ngOnInit(): void { this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); } + + addStudent() { + this.store.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 adf0ad3c1..1d6bf1989 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,16 +1,32 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { + ChangeDetectionStrategy, + Component, + inject, + OnInit, +} 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: ` + customClass="bg-light-red" + (add)="addTeacher()"> + + + + + `, styles: [ ` @@ -19,16 +35,24 @@ import { CardComponent } from '../../ui/card/card.component'; } `, ], - imports: [CardComponent], + imports: [CardComponent, ListItemComponent], + changeDetection: ChangeDetectionStrategy.OnPush, }) 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/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts index 1c3c28081..ca65d9fb0 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,14 +1,12 @@ -import { NgOptimizedImage } from '@angular/common'; -import { Component, inject, input } from '@angular/core'; -import { CityStore } from '../../data-access/city.store'; +import { CommonModule, NgOptimizedImage } from '@angular/common'; import { - randStudent, - randTeacher, - randomCity, -} 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'; + Component, + ContentChild, + EventEmitter, + input, + Output, + TemplateRef, +} from '@angular/core'; import { ListItemComponent } from '../list-item/list-item.component'; @Component({ @@ -17,62 +15,29 @@ import { ListItemComponent } from '../list-item/list-item.component';
- @if (type() === CardType.TEACHER) { - - } - @if (type() === CardType.STUDENT) { - - } - @if (type() === CardType.CITY) { - - } - +
- @for (item of list(); track item) { - @if (type() === CardType.TEACHER || type() === CardType.STUDENT) { - - } - - @if (type() === CardType.CITY) { - - } - } + + +
`, - imports: [ListItemComponent, NgOptimizedImage], + imports: [ListItemComponent, NgOptimizedImage, CommonModule], }) export class CardComponent { - private teacherStore = inject(TeacherStore); - private studentStore = inject(StudentStore); - private cityStore = inject(CityStore); + @Output() add = new EventEmitter(); + + @ContentChild('rowRef') rowTemplate!: TemplateRef; 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()); - } else if (type === CardType.CITY) { - this.cityStore.addOne(randomCity()); - } - } } 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 519a71e9e..5f563c2fc 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,20 +1,17 @@ import { ChangeDetectionStrategy, Component, - inject, + EventEmitter, input, + Output, } from '@angular/core'; -import { CityStore } from '../../data-access/city.store'; -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() }} -
@@ -22,22 +19,8 @@ import { CardType } from '../../model/card.model'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ListItemComponent { - private teacherStore = inject(TeacherStore); - private studentStore = inject(StudentStore); - private cityStore = inject(CityStore); + @Output() delete = new EventEmitter(); 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); - } else if (type === CardType.CITY) { - this.cityStore.deleteOne(id); - } - } }