Activity 33: Angular Recipe Grid
recipe.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { Recipe } from '../Models/recipe.model';
@Injectable({
providedIn: 'root'
})
export class RecipeService {
private recipes: Recipe[] = [
{
id: 1,
name: 'Spaghetti Aglio e Olio',
description: 'Simple and flavorful pasta with garlic and olive oil.',
image: 'assets/Spaghetti.jpg',
category: 'Main Course',
ingredients: [
'200g spaghetti',
'4 cloves garlic, thinly sliced',
'1/4 tsp red pepper flakes',
'1/4 cup olive oil',
'Salt and pepper to taste',
'Fresh parsley, chopped',
'Parmesan cheese (optional)',
],
},
{
id: 2,
name: 'Classic Caesar Salad',
description: 'Crisp romaine lettuce tossed with creamy Caesar dressing.',
image: 'assets/Classic-Caesar-Salad.jpg',
category: 'Appetizer',
ingredients: [
'4 cups romaine lettuce, chopped',
'1/2 cup Caesar dressing',
'1/4 cup croutons',
'1/4 cup grated Parmesan cheese',
'1 tsp lemon juice',
'Freshly ground black pepper',
],
},
{
id: 3,
name: 'Chicken Stir-Fry',
description: 'Quick and healthy stir-fried chicken and vegetables.',
image: 'assets/Chicken-Stir-Fry.jpg',
category: 'Main Course',
ingredients: [
'2 chicken breasts, thinly sliced',
'1 cup broccoli florets',
'1/2 red bell pepper, sliced',
'1/2 yellow bell pepper, sliced',
'2 tbsp soy sauce',
'1 tbsp sesame oil',
'1 tsp grated ginger',
'2 cloves garlic, minced',
'1 tbsp honey',
],
},
{
id: 4,
name: 'Beef Tacos',
description: 'Soft tacos filled with seasoned beef and fresh toppings.',
image: 'assets/Beef-Tacos.jpg',
category: 'Main Course',
ingredients: [
'500g ground beef',
'1 onion, chopped',
'1 tbsp taco seasoning',
'1/2 cup salsa',
'8 taco shells',
'Shredded lettuce',
'Chopped tomatoes',
'Grated cheese',
'Sour cream',
],
},
{
id: 5,
name: 'Caprese Salad',
description: 'Fresh tomatoes, mozzarella, and basil with olive oil drizzle.',
image: 'assets/Caprese-Salad.jpg',
category: 'Appetizer',
ingredients: [
'2 large tomatoes, sliced',
'1 ball fresh mozzarella, sliced',
'Fresh basil leaves',
'2 tbsp balsamic vinegar',
'2 tbsp olive oil',
'Salt and pepper to taste',
],
},
{
id: 6,
name: 'Vegetable Soup',
description: 'A hearty soup loaded with fresh vegetables.',
image: 'assets/Vegetable-Soup.jpg',
category: 'Soup',
ingredients: [
'1 onion, chopped',
'2 carrots, sliced',
'2 celery stalks, chopped',
'2 potatoes, diced',
'1 zucchini, chopped',
'4 cups vegetable broth',
'1 can diced tomatoes',
'Salt and pepper to taste',
'Fresh herbs like thyme and parsley',
],
},
{
id: 7,
name: 'Grilled Cheese Sandwich',
description: 'Crispy sandwich with gooey melted cheese inside.',
image: 'assets/Grilled-Cheese-Sandwich.jpg',
category: 'Snack',
ingredients: [
'2 slices of bread',
'2 tbsp butter',
'2 slices cheddar cheese',
],
},
{
id: 8,
name: 'Margarita Pizza',
description: 'Traditional Italian pizza with tomato, mozzarella, and basil.',
image: 'assets/Margarita-Pizza.jpg',
category: 'Main Course',
ingredients: [
'1 pizza dough',
'1/2 cup tomato sauce',
'1 1/2 cups mozzarella cheese, shredded',
'Fresh basil leaves',
'1 tbsp olive oil',
'Salt and pepper to taste',
],
},
{
id: 9,
name: 'Chicken Alfredo Pasta',
description: 'Creamy Alfredo pasta topped with grilled chicken.',
image: 'assets/Chicken-Alfredo-Pasta.jpg',
category: 'Main Course',
ingredients: [
'2 chicken breasts, grilled and sliced',
'200g fettuccine pasta',
'1 cup heavy cream',
'1/2 cup Parmesan cheese, grated',
'2 tbsp butter',
'2 cloves garlic, minced',
'Salt and pepper to taste',
],
},
{
id: 10,
name: 'Pancakes',
description: 'Fluffy breakfast pancakes served with syrup.',
image: 'assets/Pancakes.jpg',
category: 'Breakfast',
ingredients: [
'1 cup all-purpose flour',
'1 tbsp sugar',
'2 tsp baking powder',
'1/2 tsp salt',
'1 cup milk',
'1 egg',
'2 tbsp melted butter',
'Maple syrup for serving',
],
},
];
getRecipes(): Observable<Recipe[]> {
return of(this.recipes);
}
}
recipe.model.ts
export interface Recipe {
id: number;
name: string;
description: string;
image: string;
category: string;
ingredients: string[];
}
recipe.component.ts
import { Component, OnInit } from '@angular/core';
import { Recipe } from '../../Models/recipe.model';
import { RecipeService } from '../../services/recipe.service';
@Component({
selector: 'app-recipe',
standalone: false,
templateUrl: './recipe.component.html',
styleUrls: ['./recipe.component.css']
})
export class RecipeComponent implements OnInit {
recipes: Recipe[] = [];
currentView: 'mobile' | 'tablet' | 'desktop' = 'desktop';
expandedRecipeId: number | null = null;
constructor(private recipeService: RecipeService) {
this.checkScreenSize();
}
ngOnInit(): void {
this.loadRecipes();
window.addEventListener('resize', () => this.checkScreenSize());
}
toggleIngredients(recipeId: number): void {
this.expandedRecipeId = this.expandedRecipeId === recipeId ? null : recipeId;
}
private loadRecipes(): void {
this.recipeService.getRecipes().subscribe(
recipes => this.recipes = recipes
);
}
private checkScreenSize(): void {
const width = window.innerWidth;
if (width < 768) {
this.currentView = 'mobile';
} else if (width < 1024) {
this.currentView = 'tablet';
} else {
this.currentView = 'desktop';
}
}
setView(view: 'mobile' | 'tablet' | 'desktop'): void {
this.currentView = view;
}
}
recipe.component.html
<nav class="navbar">
<div class="navbar__brand">RECIPE</div>
</nav>
<div class="recipe-grid" [class]="'recipe-grid--' + currentView">
<div class="recipe-card" *ngFor="let recipe of recipes">
<div class="recipe-card__image">
<img [src]="recipe.image" [alt]="recipe.name">
</div>
<div class="recipe-card__content">
<h3 class="recipe-card__title">{{ recipe.name }}</h3>
<p class="recipe-card__description">{{ recipe.description }}</p>
<div class="recipe-card__info">
<button
class="ingredients-toggle"
(click)="toggleIngredients(recipe.id)">
{{ expandedRecipeId === recipe.id ? '๐ผ' : '๐ฝ' }}
</button>
</div>
<div class="ingredients-list" *ngIf="expandedRecipeId === recipe.id">
<h4>Ingredients:</h4>
<ul>
<li *ngFor="let ingredient of recipe.ingredients">
{{ ingredient }}
</li>
</ul>
</div>
</div>
</div>
</div>
OUTPUT:
GitHub link: isaaczacck/Angular-Recipe
ย