Skip to content

Commit

Permalink
feat: resolve projection of Answer:1
Browse files Browse the repository at this point in the history
  • Loading branch information
al-march committed Nov 4, 2024
1 parent c0af4fa commit b52f4b4
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -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: `
<app-card [list]="cities()" (add)="addCity()">
<img src="assets/img/city.png" width="200px" alt="student" />
<ng-template appListItemTemplate let-city>
<app-list-item (deleteItem)="deleteCity(city.id)">
{{ city.name }}
</app-list-item>
</ng-template>
</app-card>
`,
standalone: true,
imports: [],
imports: [CardComponent, ListItemTemplateDirective, ListItemComponent],
})
export class CityCardComponent implements OnInit {
constructor() {}
cities: Signal<City[]> = 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);
}
}
Original file line number Diff line number Diff line change
@@ -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: `
<app-card
[list]="students"
[type]="cardType"
customClass="bg-light-green"></app-card>
<app-card class="bg-light-green" [list]="students()" (add)="addStudent()">
<img src="assets/img/student.webp" width="200px" alt="student" />
<ng-template appListItemTemplate let-student>
<app-list-item (deleteItem)="deleteStudent(student.id)">
{{ student.firstName }}
</app-list-item>
</ng-template>
</app-card>
`,
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,
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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: `
<app-card
[list]="teachers"
[type]="cardType"
customClass="bg-light-red"></app-card>
<app-card class="bg-light-red" [list]="teachers()" (add)="addTeacher()">
<img src="assets/img/teacher.png" width="200px" alt="teacher" />
<ng-template appListItemTemplate let-teacher>
<app-list-item (deleteItem)="deleteTeacher(teacher.id)">
{{ teacher.firstName }}
</app-list-item>
</ng-template>
</app-card>
`,
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<Teacher[]> = toSignal(this.store.teachers$, {
initialValue: [],
});

constructor(
private http: FakeHttpService,
Expand All @@ -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);
}
}
4 changes: 2 additions & 2 deletions apps/angular/1-projection/src/app/data-access/city.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
77 changes: 32 additions & 45 deletions apps/angular/1-projection/src/app/ui/card/card.component.ts
Original file line number Diff line number Diff line change
@@ -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: `
<div
class="flex w-fit flex-col gap-3 rounded-md border-2 border-black p-4"
[class]="customClass">
<img
*ngIf="type === CardType.TEACHER"
src="assets/img/teacher.png"
width="200px" />
<img
*ngIf="type === CardType.STUDENT"
src="assets/img/student.webp"
width="200px" />
<ng-content select="img" />
<section>
<app-list-item
*ngFor="let item of list"
[name]="item.firstName"
[id]="item.id"
[type]="type"></app-list-item>
</section>
<section>
@for (item of list(); track item) {
<ng-template
[ngTemplateOutlet]="itemTemplate()?.templateRef ?? null"
[ngTemplateOutletContext]="{ $implicit: item }" />
}
</section>
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
</div>
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
`,
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<T> {
list = input<T[]>([]);

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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Directive, TemplateRef } from '@angular/core';

@Directive({
selector: '[appListItemTemplate]',
standalone: true,
})
export class ListItemTemplateDirective {
constructor(public templateRef: TemplateRef<unknown>) {}
}
Original file line number Diff line number Diff line change
@@ -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: `
<div class="border-grey-300 flex justify-between border px-2 py-1">
{{ name }}
<button (click)="delete(id)">
<img class="h-5" src="assets/svg/trash.svg" />
</button>
</div>
<ng-content />
<button (click)="deleteItem.emit()">
<img class="h-5" src="assets/svg/trash.svg" alt="delete" />
</button>
`,
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();
}

0 comments on commit b52f4b4

Please sign in to comment.