Activity 32: Angular Library Grid
The purpose of the Books
interface is to define a consistent structure for book objects in your Angular application. It ensures that whenever you work with a book, it has all the necessary details like its ID, title, author, genre, and an image URL. This helps prevent errors and makes the code easier to manage, especially when handling book data in components, services, or APIs. It's like setting rules to make sure every book object is complete and correctly formatted.
// book.model.ts
export interface Books {
bookID: number;
bookTitle: string;
author: string;
genre: string;
image: string;
}
// book.service.ts
import { Injectable } from '@angular/core';
import { Books } from './books';
@Injectable({
providedIn: 'root',
})
export class BooksService {
constructor() {}
private booklist: Books[] = [
{
bookID: 1,
bookTitle: 'To Kill a Mockingbird',
genre: 'Fiction',
author: 'Harper Lee',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS68RY84hFCFEv79YFlT9_dhetWuxhIO9Un6w&s',
},
{
bookID: 2,
bookTitle: 'The catcher in the rye',
genre: 'Fiction',
author: 'J.D Salinger',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSxmaay9kLmr69JLsXnSzLtEIdw6v0pNMQARg&s',
},
{
bookID: 3,
bookTitle: 'Pride and Prejudice',
genre: 'Fiction',
author: 'J.D Salinger',
image:
'https://images-na.ssl-images-amazon.com/images/S/compressed.photo.goodreads.com/books/1320399351i/1885.jpg',
},
{
bookID: 4,
bookTitle: 'Romeo and Juliet',
genre: 'Fiction',
author: 'William Shakespear',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQo9CwLCGNtv7Ywx_Rr3slD_oE190A2KvGvng&s',
},
{
bookID: 5,
bookTitle: '1984',
genre: 'Fiction',
author: 'George Orwell',
image:
'https://d3525k1ryd2155.cloudfront.net/f/935/524/9780451524935.RH.0.m.jpg',
},
{
bookID: 6,
bookTitle: 'Hamlet',
genre: 'Fiction',
author: 'William Shakespear',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSSHjZWUiPR-paryJXkATaigCJhhFrZrys4XA&s',
},
{
bookID: 7,
bookTitle: 'Brave New World',
genre: 'Fiction',
author: 'Aldous Leonard Huxley',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTzKGL7JRnlQuFYM59VIpLa20kjhjpvfJawMA&s',
},
{
bookID: 8,
bookTitle: 'The fellowship of the Ring',
genre: 'Fiction',
author: 'J.R.R Tolkien',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTaT8GXFdSmDSwqZPCEvkBryTncntoVBJUe_A&s',
},
];
getBooks(): Books[] {
return this.booklist;
}
}
The
BooksService
is marked with the@Injectable
decorator and registered as a singleton service in theroot
injector. This means it can be injected and used throughout the application.A private property,
booklist
, is defined to store an array of book objects. Each object follows theBooks
interface, ensuring a consistent structure with properties likebookID
,bookTitle
,author
,genre
, andimage
.The
getBooks()
method is a public function that simply returns thebooklist
array. This allows other parts of the application (like components) to access the list of books.When a component or another service needs the list of books, it injects this
BooksService
and calls thegetBooks()
method to fetch the data. This keeps the book data centralized and accessible in one place.
The
BooksComponent
is designed to display a list of books. It declares abooks
property, initialized as an empty array, to store the retrieved book data.The
BooksService
is injected into the component using the constructor. This allows the component to access the methods of the service.In the
ngOnInit()
lifecycle method, the component calls thegetBooks()
method from theBooksService
to fetch the list of books. The returned data is then assigned to thebooks
property.The fetched books are logged to the console for debugging and can also be used in the component's template for display. This shows how the component interacts with the service to manage and display data.
//book.component.ts
import { Component } from '@angular/core';
import { Books } from './books';
import { BooksService } from './books.service';
@Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrl: './books.component.css'
})
export class BooksComponent {
books: Books[] = [];
constructor(private bookService: BooksService) {}
ngOnInit(): void {
this.books = this.bookService.getBooks();
console.log(this.books);
}
}
The outermost
<div>
with thewrapper
class acts as a container for all the content.Inside the
wrapper
, there is awrapper__content
div that holds the dynamically generated book cards. The*ngFor
directive iterates over thebooks
array, creating onewrapper__content-card
div for each book.Each card displays the book's data:
An
<img>
element dynamically sets the source ([src]
) to the book'simage
property.The
card__title
displays the book's title using{{ book.bookTitle }}
.The
card__author
shows the author of the book with{{
book.author
}}
.
The static
card__rating
section displays a star-based rating for the book. Currently, the stars are hardcoded, but they can be made dynamic in the future.Two buttons are added for interaction:
"Available" (styled as a primary button).
"View Details" (styled as a secondary button).
<div class="wrapper">
<div class="wrapper__content">
<div *ngFor="let book of books" class="wrapper__content-card">
<img [src]="book.image" class="card__image" />
<div class="card__content">
<h3 class="card__title">{{ book.bookTitle }}</h3>
<p class="card__author">{{ book.author }}</p>
<p class="card__rating">
Rating:<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i
><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>
<i class="fa-regular fa-star"></i>
</p>
<button class="btn btn-primary">Available</button> <br />
<button class="btn btn-secondary">View Details</button>
</div>
</div>
</div>
</div>
.wrapper
:
This class is applied to the main container, giving it an orange border, padding of3rem
, and a minimum height of100vh
(making sure it takes up at least the full height of the viewport)..wrapper__content
:
Inside the wrapper, this class is used for the layout of the book cards. It uses Flexbox to arrange the cards, with a gap of3rem
between them. Theflex-wrap: wrap;
allows the cards to wrap onto new lines when the space is filled. It also centers the cards both horizontally and vertically withjustify-content: center;
andalign-items: center;
..card__image
:
The images inside each book card are constrained to a height of200px
and width of150px
to maintain a consistent size..wrapper__content-card
:
This class is applied to the individual book cards. The cards have a background color of#F5F8FA
, a width of208px
, and padding of3rem
. The content is displayed in a vertical column with Flexbox (flex-direction: column;
), and the items are centered within each card (align-items: center;
)..card__content
:
This is the section within each card where the book's title, author, and buttons are displayed. It has a top margin (margin-top: 1rem;
) and aline-height
of2
to ensure the text is spaced out evenly. (Note:background-color: lightblue;
is commented out but can be enabled for styling.).btn
:
This class styles both buttons with padding, no borders, a12px
border-radius for rounded corners, and a small right margin to separate them when placed next to each other..btn-primary
:
This class styles the "Available" button with a border color ofrgba(6, 178, 3, 0.695)
(a shade of green) and a transparent background..btn-secondary
:
The "View Details" button is styled with a background color ofrgba(6, 178, 3, 0.507)
(a lighter green), no border, and white text to contrast with the background color.
.wrapper {
border: 2px solid orange;
min-height: 100vh;
padding: 3rem;
}
.wrapper__content {
display: flex;
gap: 3rem;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.card__image {
height: 200px;
width: 150px;
}
.wrapper__content-card {
background-color: #F5F8FA;
height:auto;
width: 208px;
padding: 3rem;
display: flex;
flex-direction: column;
align-items: center;
}
.card__content {
/* background-color: lightblue; */
width: 100%;
margin-top: 1rem;
line-height: 2;
}
.btn {
padding: 5px 10px;
border: none;
margin-right: 3px;
border-radius: 12px;
}
.btn-primary {
border: 2px solid rgba(6, 178, 3, 0.695);
background: transparent;
}
.btn-secondary {
background: rgba(6, 178, 3, 0.507);
border: none;
color: white;
}
github repository: https://github.com/thisisnotsnorlax/AngularLIbraryGrid.git
Firebase: https://angularlibrarygrid.web.app/