Skip to content
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgOptimizedImage } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
inject,
OnInit,
} from '@angular/core';
import { CityStore } from '../../data-access/city.store';
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: 'TODO City',
imports: [],
template: `
<ng-template #configurableList let-item>
<app-list-item>
<span>{{ item.name }}</span>
<button (click)="delete(item.id)">
<img class="h-5" src="assets/svg/trash.svg" />
</button>
</app-list-item>
</ng-template>
<app-card
[list]="cities()"
[cardContent]="configurableList"
[customBgColor]="bgColor">
<img ngSrc="assets/img/city.png" width="200" height="200" />
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
</app-card>
`,
imports: [ListItemComponent, CardComponent, NgOptimizedImage],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CityCardComponent {}
export class CityCardComponent implements OnInit {
private http = inject(FakeHttpService);
private store = inject(CityStore);
cities = this.store.cities;
bgColor = { 'background-color': 'rgba(0, 0, 250, 0.1)' };

ngOnInit(): void {
this.http.fetchCities$.subscribe((c) => this.store.addAll(c));
}

delete(id: number) {
this.store.deleteOne(id);
}

addNewItem() {
this.store.addOne(randomCity());
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
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 { ListItemComponent } from '../../ui/list-item/list-item.component';

@Component({
selector: 'app-student-card',
template: `
<ng-template #configurableList let-item>
<app-list-item>
<span>{{ item.firstName }}</span>
<button (click)="delete(item.id)">
<img class="h-5" src="assets/svg/trash.svg" />
</button>
</app-list-item>
</ng-template>
<app-card
[list]="students()"
[type]="cardType"
customClass="bg-light-green" />
[cardContent]="configurableList"
[customBgColor]="bgColor">
<img ngSrc="assets/img/student.webp" width="200" height="200" />
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
</app-card>
`,
styles: [
`
::ng-deep .bg-light-green {
background-color: rgba(0, 250, 0, 0.1);
}
`,
],
imports: [CardComponent],
imports: [CardComponent, NgOptimizedImage, ListItemComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StudentCardComponent implements OnInit {
private http = inject(FakeHttpService);
private store = inject(StudentStore);

students = this.store.students;
cardType = CardType.STUDENT;
bgColor = { 'background-color': 'rgba(0, 250, 0, 0.1)' };

ngOnInit(): void {
this.http.fetchStudents$.subscribe((s) => this.store.addAll(s));
}

addNewItem() {
this.store.addOne(randStudent());
}

delete(id: number) {
this.store.deleteOne(id);
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
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 { ListItemComponent } from '../../ui/list-item/list-item.component';

@Component({
selector: 'app-teacher-card',
template: `
<ng-template #configurableList let-item>
<app-list-item>
<span>{{ item.firstName }}</span>
<button (click)="delete(item.id)">
<img class="h-5" src="assets/svg/trash.svg" />
</button>
</app-list-item>
</ng-template>
<app-card
[list]="teachers()"
[type]="cardType"
customClass="bg-light-red"></app-card>
[customBgColor]="bgColor"
[cardContent]="configurableList">
<img ngSrc="assets/img/teacher.png" width="200" height="200" />
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
</app-card>
`,
styles: [
`
::ng-deep .bg-light-red {
background-color: rgba(250, 0, 0, 0.1);
}
`,
],
imports: [CardComponent],
imports: [CardComponent, NgOptimizedImage, ListItemComponent],
})
export class TeacherCardComponent implements OnInit {
private http = inject(FakeHttpService);
private store = inject(TeacherStore);

teachers = this.store.teachers;
cardType = CardType.TEACHER;
bgColor = { 'background-color': 'rgba(250, 0, 0, 0.1)' };

ngOnInit(): void {
this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t));
}

delete(id: number) {
this.store.deleteOne(id);
}

addNewItem() {
this.store.addOne(randTeacher());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { City } from '../model/city.model';
providedIn: 'root',
})
export class CityStore {
private cities = signal<City[]>([]);
cities = signal<City[]>([]);

addAll(cities: City[]) {
this.cities.set(cities);
Expand Down
58 changes: 15 additions & 43 deletions apps/angular/1-projection/src/app/ui/card/card.component.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,30 @@
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 { NgStyle, NgTemplateOutlet } from '@angular/common';
import { Component, input, TemplateRef } from '@angular/core';

@Component({
selector: 'app-card',
template: `
<div
class="flex w-fit flex-col gap-3 rounded-md border-2 border-black p-4"
[class]="customClass()">
@if (type() === CardType.TEACHER) {
<img ngSrc="assets/img/teacher.png" width="200" height="200" />
}
@if (type() === CardType.STUDENT) {
<img ngSrc="assets/img/student.webp" width="200" height="200" />
}

[ngStyle]="customBgColor()"
[style.background-color]="">
<ng-content select="img"></ng-content>
<section>
@for (item of list(); track item) {
<app-list-item
[name]="item.firstName"
[id]="item.id"
[type]="type()"></app-list-item>
@for (item of list(); track item.id) {
<ng-container
*ngTemplateOutlet="
cardContent();
context: { $implicit: item }
"></ng-container>
}
</section>

<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
<ng-content select="button"></ng-content>
</div>
`,
imports: [ListItemComponent, NgOptimizedImage],
imports: [NgTemplateOutlet, NgStyle],
})
export class CardComponent {
private teacherStore = inject(TeacherStore);
private studentStore = inject(StudentStore);

readonly list = input<any[] | null>(null);
readonly type = input.required<CardType>();
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());
}
}
readonly cardContent = input<TemplateRef<any>>();
readonly customBgColor = input<Record<string, string> | null>(null);
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,13 @@
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 } 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>
<ng-content select="span"></ng-content>
<ng-content select="button"></ng-content>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ListItemComponent {
private teacherStore = inject(TeacherStore);
private studentStore = inject(StudentStore);

readonly id = input.required<number>();
readonly name = input.required<string>();
readonly type = input.required<CardType>();

delete(id: number) {
const type = this.type();
if (type === CardType.TEACHER) {
this.teacherStore.deleteOne(id);
} else if (type === CardType.STUDENT) {
this.studentStore.deleteOne(id);
}
}
}
export class ListItemComponent {}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"node": ">=20.19.6"
},
"private": true,
"packageManager": "pnpm@10.23.0",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
Expand Down
Loading