Skip to content

Commit 37e1fc0

Browse files
author
Oleksandr Perepichai
committed
feat: 1 projection
1 parent 0d15a0b commit 37e1fc0

6 files changed

Lines changed: 129 additions & 65 deletions

File tree

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,58 @@
1-
import { ChangeDetectionStrategy, Component } from '@angular/core';
1+
import { NgOptimizedImage } from '@angular/common';
2+
import {
3+
ChangeDetectionStrategy,
4+
Component,
5+
inject,
6+
OnInit,
7+
} from '@angular/core';
8+
import { CityStore } from '../../data-access/city.store';
9+
import {
10+
FakeHttpService,
11+
randomCity,
12+
} from '../../data-access/fake-http.service';
13+
import { CardComponent } from '../../ui/card/card.component';
14+
import { ListItemComponent } from '../../ui/list-item/list-item.component';
215

316
@Component({
417
selector: 'app-city-card',
5-
template: 'TODO City',
6-
imports: [],
18+
template: `
19+
<app-card
20+
[list]="cities()"
21+
(addListItem)="addNewCity()"
22+
customClass="bg-light-blue">
23+
<img ngSrc="assets/img/city.png" width="200" height="200" />
24+
<ng-template #rowRef let-city>
25+
<app-list-item [id]="city.id" (deleteItem)="deleteCity(city.id)">
26+
{{ city.name }}
27+
</app-list-item>
28+
</ng-template>
29+
</app-card>
30+
`,
31+
styles: [
32+
`
33+
::ng-deep .bg-light-blue {
34+
background-color: rgba(0, 0, 250, 0.1);
35+
}
36+
`,
37+
],
38+
imports: [CardComponent, ListItemComponent, NgOptimizedImage],
739
changeDetection: ChangeDetectionStrategy.OnPush,
840
})
9-
export class CityCardComponent {}
41+
export class CityCardComponent implements OnInit {
42+
private http = inject(FakeHttpService);
43+
private store = inject(CityStore);
44+
45+
cities = this.store.cities;
46+
47+
ngOnInit(): void {
48+
this.http.fetchCities$.subscribe((t) => this.store.addAll(t));
49+
}
50+
51+
addNewCity() {
52+
this.store.addOne(randomCity());
53+
}
54+
55+
deleteCity(id: number) {
56+
this.store.deleteOne(id);
57+
}
58+
}
Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
1+
import { NgOptimizedImage } from '@angular/common';
12
import {
23
ChangeDetectionStrategy,
34
Component,
45
inject,
56
OnInit,
67
} from '@angular/core';
7-
import { FakeHttpService } from '../../data-access/fake-http.service';
8+
import {
9+
FakeHttpService,
10+
randStudent,
11+
} from '../../data-access/fake-http.service';
812
import { StudentStore } from '../../data-access/student.store';
9-
import { CardType } from '../../model/card.model';
1013
import { CardComponent } from '../../ui/card/card.component';
14+
import { ListItemComponent } from '../../ui/list-item/list-item.component';
1115

1216
@Component({
1317
selector: 'app-student-card',
1418
template: `
1519
<app-card
1620
[list]="students()"
17-
[type]="cardType"
18-
customClass="bg-light-green" />
21+
(addListItem)="addNewStudent()"
22+
customClass="bg-light-green">
23+
<img ngSrc="assets/img/student.webp" width="200" height="200" />
24+
<ng-template #rowRef let-student>
25+
<app-list-item
26+
[id]="student.id"
27+
(deleteItem)="deleteStudent(student.id)">
28+
{{ student.firstName }}
29+
</app-list-item>
30+
</ng-template>
31+
</app-card>
1932
`,
2033
styles: [
2134
`
@@ -24,17 +37,24 @@ import { CardComponent } from '../../ui/card/card.component';
2437
}
2538
`,
2639
],
27-
imports: [CardComponent],
40+
imports: [CardComponent, ListItemComponent, NgOptimizedImage],
2841
changeDetection: ChangeDetectionStrategy.OnPush,
2942
})
3043
export class StudentCardComponent implements OnInit {
3144
private http = inject(FakeHttpService);
3245
private store = inject(StudentStore);
3346

3447
students = this.store.students;
35-
cardType = CardType.STUDENT;
3648

3749
ngOnInit(): void {
3850
this.http.fetchStudents$.subscribe((s) => this.store.addAll(s));
3951
}
52+
53+
addNewStudent() {
54+
this.store.addOne(randStudent());
55+
}
56+
57+
deleteStudent(id: number) {
58+
this.store.deleteOne(id);
59+
}
4060
}
Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1+
import { NgOptimizedImage } from '@angular/common';
12
import { Component, inject, OnInit } from '@angular/core';
2-
import { FakeHttpService } from '../../data-access/fake-http.service';
3+
import {
4+
FakeHttpService,
5+
randTeacher,
6+
} from '../../data-access/fake-http.service';
37
import { TeacherStore } from '../../data-access/teacher.store';
4-
import { CardType } from '../../model/card.model';
58
import { CardComponent } from '../../ui/card/card.component';
9+
import { ListItemComponent } from '../../ui/list-item/list-item.component';
610

711
@Component({
812
selector: 'app-teacher-card',
913
template: `
1014
<app-card
1115
[list]="teachers()"
12-
[type]="cardType"
13-
customClass="bg-light-red"></app-card>
16+
(addListItem)="addNewTeacher()"
17+
customClass="bg-light-red">
18+
<img ngSrc="assets/img/teacher.png" width="200" height="200" />
19+
<ng-template #rowRef let-teacher>
20+
<app-list-item
21+
[id]="teacher.id"
22+
(deleteItem)="deleteTeacher(teacher.id)">
23+
{{ teacher.firstName }}
24+
</app-list-item>
25+
</ng-template>
26+
</app-card>
1427
`,
1528
styles: [
1629
`
@@ -19,16 +32,23 @@ import { CardComponent } from '../../ui/card/card.component';
1932
}
2033
`,
2134
],
22-
imports: [CardComponent],
35+
imports: [CardComponent, ListItemComponent, NgOptimizedImage],
2336
})
2437
export class TeacherCardComponent implements OnInit {
2538
private http = inject(FakeHttpService);
2639
private store = inject(TeacherStore);
2740

2841
teachers = this.store.teachers;
29-
cardType = CardType.TEACHER;
3042

3143
ngOnInit(): void {
3244
this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t));
3345
}
46+
47+
addNewTeacher() {
48+
this.store.addOne(randTeacher());
49+
}
50+
51+
deleteTeacher(id: number) {
52+
this.store.deleteOne(id);
53+
}
3454
}

apps/angular/1-projection/src/app/data-access/city.store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { City } from '../model/city.model';
55
providedIn: 'root',
66
})
77
export class CityStore {
8-
private cities = signal<City[]>([]);
8+
public cities = signal<City[]>([]);
99

1010
addAll(cities: City[]) {
1111
this.cities.set(cities);
Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
1-
import { NgOptimizedImage } from '@angular/common';
2-
import { Component, inject, input } from '@angular/core';
3-
import { randStudent, randTeacher } from '../../data-access/fake-http.service';
4-
import { StudentStore } from '../../data-access/student.store';
5-
import { TeacherStore } from '../../data-access/teacher.store';
6-
import { CardType } from '../../model/card.model';
7-
import { ListItemComponent } from '../list-item/list-item.component';
1+
import { CommonModule } from '@angular/common';
2+
import {
3+
Component,
4+
ContentChild,
5+
input,
6+
output,
7+
TemplateRef,
8+
} from '@angular/core';
89

910
@Component({
1011
selector: 'app-card',
1112
template: `
1213
<div
1314
class="flex w-fit flex-col gap-3 rounded-md border-2 border-black p-4"
1415
[class]="customClass()">
15-
@if (type() === CardType.TEACHER) {
16-
<img ngSrc="assets/img/teacher.png" width="200" height="200" />
17-
}
18-
@if (type() === CardType.STUDENT) {
19-
<img ngSrc="assets/img/student.webp" width="200" height="200" />
20-
}
21-
16+
<ng-content select="img"></ng-content>
2217
<section>
2318
@for (item of list(); track item) {
24-
<app-list-item
25-
[name]="item.firstName"
26-
[id]="item.id"
27-
[type]="type()"></app-list-item>
19+
<ng-container
20+
[ngTemplateOutlet]="rowTemplate"
21+
[ngTemplateOutletContext]="{ $implicit: item }"></ng-container>
2822
}
2923
</section>
3024
@@ -35,24 +29,17 @@ import { ListItemComponent } from '../list-item/list-item.component';
3529
</button>
3630
</div>
3731
`,
38-
imports: [ListItemComponent, NgOptimizedImage],
32+
imports: [CommonModule],
3933
})
40-
export class CardComponent {
41-
private teacherStore = inject(TeacherStore);
42-
private studentStore = inject(StudentStore);
43-
44-
readonly list = input<any[] | null>(null);
45-
readonly type = input.required<CardType>();
34+
export class CardComponent<T> {
35+
readonly list = input<T[] | null>(null);
4636
readonly customClass = input('');
37+
readonly addListItem = output();
4738

48-
CardType = CardType;
39+
@ContentChild('rowRef', { read: TemplateRef })
40+
rowTemplate!: TemplateRef<{ $implicit: T }>;
4941

5042
addNewItem() {
51-
const type = this.type();
52-
if (type === CardType.TEACHER) {
53-
this.teacherStore.addOne(randTeacher());
54-
} else if (type === CardType.STUDENT) {
55-
this.studentStore.addOne(randStudent());
56-
}
43+
this.addListItem.emit();
5744
}
5845
}
Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import {
22
ChangeDetectionStrategy,
33
Component,
4-
inject,
54
input,
5+
output,
66
} from '@angular/core';
7-
import { StudentStore } from '../../data-access/student.store';
8-
import { TeacherStore } from '../../data-access/teacher.store';
9-
import { CardType } from '../../model/card.model';
107

118
@Component({
129
selector: 'app-list-item',
1310
template: `
1411
<div class="border-grey-300 flex justify-between border px-2 py-1">
15-
{{ name() }}
12+
<ng-content></ng-content>
1613
<button (click)="delete(id())">
1714
<img class="h-5" src="assets/svg/trash.svg" />
1815
</button>
@@ -22,19 +19,10 @@ import { CardType } from '../../model/card.model';
2219
changeDetection: ChangeDetectionStrategy.OnPush,
2320
})
2421
export class ListItemComponent {
25-
private teacherStore = inject(TeacherStore);
26-
private studentStore = inject(StudentStore);
27-
2822
readonly id = input.required<number>();
29-
readonly name = input.required<string>();
30-
readonly type = input.required<CardType>();
23+
readonly deleteItem = output<number>();
3124

3225
delete(id: number) {
33-
const type = this.type();
34-
if (type === CardType.TEACHER) {
35-
this.teacherStore.deleteOne(id);
36-
} else if (type === CardType.STUDENT) {
37-
this.studentStore.deleteOne(id);
38-
}
26+
this.deleteItem.emit(id);
3927
}
4028
}

0 commit comments

Comments
 (0)