@@ -13,7 +13,16 @@
|
|
13 |
<section>
|
14 |
<h1>Books</h1>
|
15 |
<div>
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
<app-book-item [book]="b" (like)="addLikedBook($event)" />
|
18 |
}
|
19 |
</div>
|
|
|
13 |
<section>
|
14 |
<h1>Books</h1>
|
15 |
<div>
|
16 |
+
<input
|
17 |
+
type="search"
|
18 |
+
#searchInput
|
19 |
+
(input)="this.searchTerm.set(searchInput.value)"
|
20 |
+
[value]="this.searchTerm()"
|
21 |
+
placeholder="Search"
|
22 |
+
aria-label="Search"
|
23 |
+
/>
|
24 |
+
|
25 |
+
@for (b of filteredBooks(); track b.isbn) {
|
26 |
<app-book-item [book]="b" (like)="addLikedBook($event)" />
|
27 |
}
|
28 |
</div>
|
@@ -1,4 +1,4 @@
|
|
1 |
-
import { Component, inject, signal } from '@angular/core';
|
2 |
|
3 |
import { Book } from '../../shared/book';
|
4 |
import { BookItem } from '../book-item/book-item';
|
@@ -13,9 +13,20 @@ import { BookStore } from '../../shared/book-store';
|
|
13 |
export class BookList {
|
14 |
#store = inject(BookStore);
|
15 |
|
|
|
|
|
16 |
readonly books = signal<Book[]>([]);
|
17 |
readonly likedBooks = signal<Book[]>([]);
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
constructor() {
|
20 |
this.books.set(this.#store.getBookList());
|
21 |
}
|
|
|
1 |
+
import { Component, computed, inject, signal } from '@angular/core';
|
2 |
|
3 |
import { Book } from '../../shared/book';
|
4 |
import { BookItem } from '../book-item/book-item';
|
|
|
13 |
export class BookList {
|
14 |
#store = inject(BookStore);
|
15 |
|
16 |
+
readonly searchTerm = signal('');
|
17 |
+
|
18 |
readonly books = signal<Book[]>([]);
|
19 |
readonly likedBooks = signal<Book[]>([]);
|
20 |
|
21 |
+
readonly filteredBooks = computed(() => {
|
22 |
+
if (!this.searchTerm()) {
|
23 |
+
return this.books();
|
24 |
+
}
|
25 |
+
|
26 |
+
const term = this.searchTerm().toLowerCase();
|
27 |
+
return this.books().filter((b) => b.title.toLowerCase().includes(term));
|
28 |
+
});
|
29 |
+
|
30 |
constructor() {
|
31 |
this.books.set(this.#store.getBookList());
|
32 |
}
|