Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<p align='center' style='font-weight:bold'>Collection of Angular challenges</p>

<br>
adsfsadfasd

## Intro

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, computed, inject } from '@angular/core';
import { CityStore } from '../../data-access/city.store';
import {
FakeHttpService,
randomCity,
} from '../../data-access/fake-http.service';
import { CardListItem } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';

@Component({
selector: 'app-city-card',
template: 'TODO City',
imports: [],
template: `
<app-card
[list]="cityListItems()"
class="bg-light-green"
(addNewItemEvent)="handleAddNewItemEvent()"
(deleteItemEvent)="handleDeleteItemEvent($event)">
<div card-img>
<img src="assets/img/city.png" width="200px" />
</div>
</app-card>
`,
styles: [
`
.bg-light-green {
background-color: rgba(0, 250, 0, 0.1);
}
`,
],
imports: [CardComponent],
})
export class CityCardComponent implements OnInit {
constructor() {}
private http = inject(FakeHttpService);
private store = inject(CityStore);

ngOnInit(): void {}
cityListItems = computed<CardListItem[]>(() =>
this.store.cities().map((city) => ({
name: city.name,
id: city.id,
})),
);

ngOnInit(): void {
this.http.fetchCities$.subscribe((e) => this.store.addAll(e));
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use imperative coding, try to code in a declaration way, which means try to do the same but without the subscribe.

And use signals. 😉

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thank you, declarative seems like a trend in Angular, especially with signals.
I will try to adapt it. I understand that such a style is safer than mutating the state.


handleAddNewItemEvent() {
this.store.addOne(randomCity());
}

handleDeleteItemEvent(id: number) {
this.store.deleteOne(id);
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
import { Component, OnInit } from '@angular/core';
import { FakeHttpService } from '../../data-access/fake-http.service';
import { Component, OnInit, computed, inject } from '@angular/core';
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 { CardListItem } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';

@Component({
selector: 'app-student-card',
template: `
<app-card
[list]="students"
[type]="cardType"
customClass="bg-light-green"></app-card>
[list]="studentListItems()"
class="bg-light-green"
(addNewItemEvent)="handleAddNewItemEvent()"
(deleteItemEvent)="handleDeleteItemEvent($event)">
<div card-img>
<img src="assets/img/student.webp" width="200px" />
</div>
</app-card>
`,
styles: [
`
::ng-deep .bg-light-green {
.bg-light-green {
background-color: rgba(0, 250, 0, 0.1);
}
`,
],
imports: [CardComponent],
})
export class StudentCardComponent implements OnInit {
students: Student[] = [];
cardType = CardType.STUDENT;
private http = inject(FakeHttpService);
private store = inject(StudentStore);

constructor(
private http: FakeHttpService,
private store: StudentStore,
) {}
students = this.store.students;

studentListItems = computed<CardListItem[]>(() =>
this.store.students().map((student) => ({
name: student.firstName,
id: student.id,
})),
);

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

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

this.store.students$.subscribe((s) => (this.students = s));
handleDeleteItemEvent(id: number) {
this.store.deleteOne(id);
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
import { Component, OnInit } from '@angular/core';
import { FakeHttpService } from '../../data-access/fake-http.service';
import { Component, OnInit, computed, inject } 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 { Teacher } from '../../model/teacher.model';
import { CardListItem } from '../../model/card.model';
import { CardComponent } from '../../ui/card/card.component';

@Component({
selector: 'app-teacher-card',
template: `
<app-card
[list]="teachers"
[type]="cardType"
customClass="bg-light-red"></app-card>
[list]="teacherListItems()"
class="bg-light-red"
(addNewItemEvent)="handleAddNewItemEvent()"
(deleteItemEvent)="handleDeleteItemEvent($event)">
<div card-img>
<img src="assets/img/teacher.png" width="200px" />
</div>
</app-card>
`,
styles: [
`
::ng-deep .bg-light-red {
.bg-light-red {
background-color: rgba(250, 0, 0, 0.1);
}
`,
],
imports: [CardComponent],
})
export class TeacherCardComponent implements OnInit {
teachers: Teacher[] = [];
cardType = CardType.TEACHER;
private http = inject(FakeHttpService);
private store = inject(TeacherStore);

constructor(
private http: FakeHttpService,
private store: TeacherStore,
) {}
teacherListItems = computed<CardListItem[]>(() =>
this.store
.teachers()
.map((teacher) => ({ name: teacher.firstName, id: teacher.id })),
);

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

handleAddNewItemEvent() {
this.store.addOne(randTeacher());
}

this.store.teachers$.subscribe((t) => (this.teachers = t));
handleDeleteItemEvent(id: number) {
this.store.deleteOne(id);
}
}
14 changes: 6 additions & 8 deletions apps/angular/1-projection/src/app/data-access/city.store.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Injectable, signal } from '@angular/core';
import { City } from '../model/city.model';

@Injectable({
providedIn: 'root',
})
export class CityStore {
private cities = new BehaviorSubject<City[]>([]);
cities$ = this.cities.asObservable();
public cities = signal<City[]>([]);

addAll(cities: City[]) {
this.cities.next(cities);
this.cities.set(cities);
}

addOne(student: City) {
this.cities.next([...this.cities.value, student]);
addOne(city: City) {
this.cities.set([...this.cities(), city]);
}

deleteOne(id: number) {
this.cities.next(this.cities.value.filter((s) => s.id !== id));
this.cities.set(this.cities().filter((s) => s.id !== id));
}
}
12 changes: 5 additions & 7 deletions apps/angular/1-projection/src/app/data-access/student.store.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Injectable, signal } from '@angular/core';
import { Student } from '../model/student.model';

@Injectable({
providedIn: 'root',
})
export class StudentStore {
private students = new BehaviorSubject<Student[]>([]);
students$ = this.students.asObservable();
public students = signal<Student[]>([]);

addAll(students: Student[]) {
this.students.next(students);
this.students.set(students);
}

addOne(student: Student) {
this.students.next([...this.students.value, student]);
this.students.set([...this.students(), student]);
}

deleteOne(id: number) {
this.students.next(this.students.value.filter((s) => s.id !== id));
this.students.set(this.students().filter((s) => s.id !== id));
}
}
12 changes: 5 additions & 7 deletions apps/angular/1-projection/src/app/data-access/teacher.store.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Injectable, signal } from '@angular/core';
import { Teacher } from '../model/teacher.model';

@Injectable({
providedIn: 'root',
})
export class TeacherStore {
private teachers = new BehaviorSubject<Teacher[]>([]);
teachers$ = this.teachers.asObservable();
public teachers = signal<Teacher[]>([]);

addAll(teachers: Teacher[]) {
this.teachers.next(teachers);
this.teachers.set(teachers);
}

addOne(teacher: Teacher) {
this.teachers.next([...this.teachers.value, teacher]);
this.teachers.set([...this.teachers(), teacher]);
}

deleteOne(id: number) {
this.teachers.next(this.teachers.value.filter((t) => t.id !== id));
this.teachers.set(this.teachers().filter((t) => t.id !== id));
}
}
5 changes: 5 additions & 0 deletions apps/angular/1-projection/src/app/model/card.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ export enum CardType {
STUDENT,
CITY,
}

export interface CardListItem {
name: string;
id: number;
}
71 changes: 25 additions & 46 deletions apps/angular/1-projection/src/app/ui/card/card.component.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,39 @@
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 { Component, input, output } from '@angular/core';
import { CardListItem } from '../../model/card.model';
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" />

<section>
<ng-content select="[card-img]"></ng-content>
<section>
@for (item of list(); track $index) {
<app-list-item
*ngFor="let item of list"
[name]="item.firstName"
[name]="item.name"
[id]="item.id"
[type]="type"></app-list-item>
</section>

<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
</div>
(deleteItemEvent)="handleDeleteItemEvent($event)" />
}
</section>
<button
class="rounded-sm border border-blue-500 bg-blue-300 p-2"
(click)="addNewItem()">
Add
</button>
`,
imports: [NgIf, NgFor, ListItemComponent],
imports: [ListItemComponent],
host: {
class: 'border-2 border-black rounded-md p-4 w-fit flex flex-col gap-3',
},
})
export class CardComponent {
@Input() list: any[] | null = null;
@Input() type!: CardType;
@Input() customClass = '';

CardType = CardType;

constructor(
private teacherStore: TeacherStore,
private studentStore: StudentStore,
) {}
list = input<CardListItem[]>([]);
deleteItemEvent = output<number>();
addNewItemEvent = output<void>();

addNewItem() {
if (this.type === CardType.TEACHER) {
this.teacherStore.addOne(randTeacher());
} else if (this.type === CardType.STUDENT) {
this.studentStore.addOne(randStudent());
}
this.addNewItemEvent.emit();
}
handleDeleteItemEvent(id: number) {
this.deleteItemEvent.emit(id);
}
}
Loading