Skip to content

Commit 0619dfc

Browse files
exercise 4 - Templates - Socks Shop
1 parent 8fb91ba commit 0619dfc

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

itenium-socks/package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

itenium-socks/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@angular/router": "^18.0.0",
2121
"@fortawesome/angular-fontawesome": "^0.15.0",
2222
"@fortawesome/fontawesome-free": "^6.5.2",
23+
"ngx-pagination": "^6.0.3",
2324
"rxjs": "~7.8.0",
2425
"tslib": "^2.3.0",
2526
"zone.js": "~0.14.3"

itenium-socks/src/app/socks/shop.component.html

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,33 @@ <h2>
55
Our Socks
66
</h2>
77
</div>
8+
<div>
9+
<label>
10+
Filter by Name:
11+
<input type="text" (input)="onFilterName($event)">
12+
</label>
13+
<label>
14+
Filter by Color:
15+
<input type="text" (input)="onFilterColor($event)">
16+
</label>
17+
<label>
18+
Sort by:
19+
<select (change)="onSortBy($event)">
20+
<option value="name">Name</option>
21+
<option value="price">Price</option>
22+
</select>
23+
</label>
24+
</div>
825
<div class="row">
9-
<div class="col-sm-6 col-md-4 col-lg-3" *ngFor="let sock of socks$ | async">
26+
<div class="col-sm-6 col-md-4 col-lg-3" *ngFor="let sock of filteredSocks$ | async">
1027
<div class="box">
1128
<a href="/socks/{{ sock.id }}">
1229
<div class="img-box">
1330
<img src="sock-images/Socks-{{ sock.brand }}-{{ sock.variant }}.png" />
1431
</div>
1532
<div class="detail-box">
1633
<h6>{{ sock.name }}</h6>
17-
<h6><span>{{ sock.price }}</span></h6>
34+
<h6><span>{{ sock.price | price }}</span></h6>
1835
</div>
1936
<div class="new">
2037
<span class="favourite" [style.color]="sock.color"><i class="fa fa-star"></i></span>
@@ -24,4 +41,8 @@ <h6><span>{{ sock.price }}</span></h6>
2441
</div>
2542
</div>
2643
</div>
44+
<div>
45+
<button (click)="onPageChange(currentPageSubject.value - 1)" [disabled]="currentPageSubject.value === 1">Previous</button>
46+
<button (click)="onPageChange(currentPageSubject.value + 1)">Next</button>
47+
</div>
2748
</section>
Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,78 @@
11
import { Component } from '@angular/core';
22
import { SocksService } from './socks.service';
3-
import { Observable } from 'rxjs';
3+
import { Observable,BehaviorSubject, combineLatest } from 'rxjs';
44
import { Sock } from './sock.model';
55
import { AsyncPipe, NgFor } from '@angular/common';
6+
import { NgxPaginationModule } from 'ngx-pagination';
7+
import { map } from 'rxjs/operators';
8+
import { PricePipe } from '../price.pipe';
69

710
@Component({
811
selector: 'app-shop',
912
standalone: true,
10-
imports: [NgFor, AsyncPipe],
13+
imports: [NgFor, AsyncPipe, NgxPaginationModule, PricePipe],
1114
templateUrl: './shop.component.html'
1215
})
1316
export class ShopComponent {
1417
socks$!: Observable<Sock[]>;
18+
filteredSocks$!: Observable<Sock[]>;
19+
20+
public nameFilterSubject = new BehaviorSubject<string>('');
21+
public colorFilterSubject = new BehaviorSubject<string>('');
22+
public sortBySubject = new BehaviorSubject<string>('name');
23+
public currentPageSubject = new BehaviorSubject<number>(1);
24+
public pageSize = 10;
1525

1626
constructor(private socksService: SocksService) {}
1727

1828
ngOnInit(): void {
1929
this.socks$ = this.socksService.get();
30+
31+
this.filteredSocks$ = combineLatest([
32+
this.socks$,
33+
this.nameFilterSubject.asObservable(),
34+
this.colorFilterSubject.asObservable(),
35+
this.sortBySubject.asObservable(),
36+
this.currentPageSubject.asObservable()
37+
]).pipe(
38+
map(([socks, nameFilter, colorFilter, sortBy, currentPage]) => {
39+
let filtered = socks.filter(sock =>
40+
sock.name.toLowerCase().includes(nameFilter.toLowerCase()) &&
41+
sock.variant.toLowerCase().includes(colorFilter.toLowerCase())
42+
);
43+
44+
filtered = filtered.sort((a, b) => {
45+
if (sortBy === 'name') {
46+
return a.name.localeCompare(b.name);
47+
} else if (sortBy === 'price') {
48+
return a.price - b.price;
49+
}
50+
return 0;
51+
});
52+
53+
const startIndex = (currentPage - 1) * this.pageSize;
54+
return filtered.slice(startIndex, startIndex + this.pageSize);
55+
})
56+
);
2057
}
58+
59+
onFilterName(event: Event) {
60+
const name = (event.target as HTMLInputElement).value;
61+
this.nameFilterSubject.next(name);
62+
}
63+
64+
onFilterColor(event: Event) {
65+
const color = (event.target as HTMLInputElement).value;
66+
this.colorFilterSubject.next(color);
67+
}
68+
69+
onSortBy(event: Event) {
70+
const sortBy = (event.target as HTMLInputElement).value;
71+
this.sortBySubject.next(sortBy);
72+
}
73+
74+
onPageChange(page: number) {
75+
this.currentPageSubject.next(page);
76+
}
77+
2178
}

0 commit comments

Comments
 (0)