# Activity 32: Angular Library Grid

In this activity, I will create an Angular application to display a list of books in a grid layout. The app will fetch the data from a service, display it using a component, and utilize **CSS Grid** and **Flexbox** for layout. We will also apply the **BEM CSS architecture** for clean and maintainable styles.

### **Book Model**

Create a model for the books. This will structure the book data and ensure we have a consistent format for each book.

Create the file `book.model.ts`:

```typescript

export interface Book {
  id: number;
  title: string;
  author: string;
  genre: string;
  rating: number; 
  coverImage: string; 
  isAvailable: boolean;
}
```

This model will define the structure for each book object.

### **Book Service**

Next, we create a service to manage the list of books. We will add a few books to this service with placeholder data, including book images and price.

Create the service `book.service.ts`:

```typescript
import { Injectable } from '@angular/core';
import { Book } from './book.model';

@Injectable({
  providedIn: 'root',
})
export class BookService {
  getBooks(): Book[] {
    return [
      {
        id: 1,
        title: 'Romeo and Juliet',
        author: 'William Shakespeare',
        genre: 'Fiction',
        rating: 4,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
      {
        id: 2,
        title: 'To Kill a Mockingbird',
        author: 'Harper Lee',
        genre: 'Classic',
        rating: 5,
        coverImage: 'image/Book.jpg',
        isAvailable: false,
      },
      {
        id: 3,
        title: '1984',
        author: 'George Orwell',
        genre: 'Dystopian',
        rating: 5,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
      {
        id: 4,
        title: 'Pride and Prejudice',
        author: 'Jane Austen',
        genre: 'Romance',
        rating: 4,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
      {
        id: 5,
        title: 'The Great Gatsby',
        author: 'F. Scott Fitzgerald',
        genre: 'Classic',
        rating: 4,
        coverImage: 'image/Book.jpg',
        isAvailable: false,
      },
      {
        id: 6,
        title: 'Moby Dick',
        author: 'Herman Melville',
        genre: 'Adventure',
        rating: 3,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
      {
        id: 7,
        title: 'The Catcher in the Rye',
        author: 'J.D. Salinger',
        genre: 'Classic',
        rating: 4,
        coverImage: 'image/Book.jpg',
        isAvailable: false,
      },
      {
        id: 8,
        title: 'The Hobbit',
        author: 'J.R.R. Tolkien',
        genre: 'Fantasy',
        rating: 5,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
      {
        id: 9,
        title: 'War and Peace',
        author: 'Leo Tolstoy',
        genre: 'Historical Fiction',
        rating: 5,
        coverImage: 'image/Book.jpg',
        isAvailable: false,
      },
      {
        id: 10,
        title: 'Brave New World',
        author: 'Aldous Huxley',
        genre: 'Science Fiction',
        rating: 4,
        coverImage: 'image/Book.jpg',
        isAvailable: true,
      },
    ];
  }
}
```

This service provides a list of books with relevant details, including a placeholder image and price.

### **Displaying the Books in the Component**

Now, let’s fetch and display the book data in the `book.component.ts` file. We'll also use **CSS Grid** and **Flexbox** for layout.

Create the component `book.component.ts`:

```typescript
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookService } from '../book.service';
import { Book } from '../book.model';

@Component({
  selector: 'app-book',
  standalone: true,
  templateUrl: './book.component.html',
  styleUrls: ['./book.component.css'],
  imports: [CommonModule],
})
export class BookComponent implements OnInit {
  books: Book[] = [];

  constructor(private bookService: BookService) {}

  ngOnInit(): void {
    this.books = this.bookService.getBooks();
  }
}
```

This component fetches the list of books from the `BookService` and stores them in the `books` array.

### **Creating the Book Layout Using Grid and Flex**

In the `book.component.html`, we will display the books in a grid layout with individual book cards. We’ll use **Flexbox** for aligning the content inside the book card, and **CSS Grid** for the overall layout.

Create the HTML file `book.component.html`:

```html
<div class="book-grid">
  <div class="book-card" *ngFor="let book of books">
    <img class="book-card__image" [src]="book.coverImage" [alt]="book.title" />

    <h3 class="book-card__title">{{ book.title }}</h3>

    <p class="book-card__author"><strong>Author:</strong> {{ book.author }}</p>
    <p class="book-card__genre"><strong>Genre:</strong> {{ book.genre }}</p>
    <p class="book-card__rating">
      <strong>Rating:</strong>
      <span class="stars">
        <span *ngFor="let star of [].constructor(book.rating)">★</span>
        <span *ngFor="let emptyStar of [].constructor(5 - book.rating)">☆</span>
      </span>
    </p>

    <span
      class="badge badge--available"
      *ngIf="book.isAvailable"
      >Available</span
    >
    <span
      class="badge badge--unavailable"
      *ngIf="!book.isAvailable"
      >Unavailable</span
    >

    <button class="button button--details">View Details</button>
  </div>
</div>
```

### **Styling the Book Cards Using BEM CSS Architecture**

Create the CSS for the grid layout and styling the book cards. We’ll apply **BEM CSS architecture** for maintainability and clarity.

Create the CSS file `book.component.css`:

```css
.book-grid {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(2, 1fr); /* Mobile */
  padding: 20px;
}

@media (min-width: 768px) {
  .book-grid {
    grid-template-columns: repeat(3, 1fr); /* Tablet */
  }
}

@media (min-width: 1024px) {
  .book-grid {
    grid-template-columns: repeat(5, 1fr); /* Desktop */
  }
}

/* Book Card */
.book-card {
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 15px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  text-align: left;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.book-card__image {
  width: 100%;
  height: 180px;
  object-fit: cover;
  margin-bottom: 10px;
  border-radius: 4px;
}

.book-card__title {
  font-size: 1.2rem;
  margin: 10px 0 5px;
  font-weight: bold;
  color: #333;
}

.book-card__author,
.book-card__genre,
.book-card__rating {
  font-size: 0.9rem;
  color: #666;
  margin: 5px 0;
}

.stars {
  color: #ffcc00;
}

.badge {
  display: inline-block;
  margin: 10px 0;
  padding: 5px 10px;
  border-radius: 12px;
  font-size: 0.8rem;
  font-weight: bold;
}

.badge--available {
  background-color: #28a745;
  text-align: center;
  color: #fff;
}

.badge--unavailable {
  background-color: #dc3545;
  text-align: center;
  color: #fff;
}

.button {
  background-color: #28a745;
  color: #fff;
  border: none;
  padding: 8px 15px;
  font-size: 0.9rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin-top: auto;
}

.button:hover {
  background-color: #218838;
}
```

* The `.book-container` uses **CSS Grid** for the overall layout.
    
* Each `.book-card` uses **Flexbox** for the inner layout.
    
* **BEM CSS** is used for naming conventions to maintain modularity and clarity.
    
* **2 columns for mobile**, **3 columns for tablets**, and **5 columns for desktops**
    

Github Link: [https://github.com/RodelDecio/Angular-Library-Grid.git](https://github.com/RodelDecio/Angular-Library-Grid.git)

Hosting URL: [https://angularlibrarygrid-eaa06.web.app](https://angularlibrarygrid-eaa06.web.app)
