Merge pull request 'add-recipe-form' (#1) from add-recipe-form into master
Reviewed-on: #1pull/3/head
commit
2b64147432
@ -1,3 +1,6 @@
|
|||||||
<h1> App HTML </h1>
|
<h1>Ratatouille</h1>
|
||||||
|
|
||||||
<app-recipe-list></app-recipe-list>
|
<div class="wrapper">
|
||||||
|
<app-recipe-list></app-recipe-list>
|
||||||
|
<app-recipe-form></app-recipe-form>
|
||||||
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Ingredient } from "./ingredient";
|
import { Ingredient } from "./ingredient.model";
|
||||||
|
|
||||||
export interface Recipe {
|
export interface Recipe {
|
||||||
id: number;
|
id: number;
|
@ -0,0 +1,32 @@
|
|||||||
|
<h2>New Recipe</h2>
|
||||||
|
<form [formGroup]="recipeForm" (ngSubmit)="onSubmit()">
|
||||||
|
<label for="name">Name:</label>
|
||||||
|
<input id="name" formControlName="name">
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<label for="description">Description:</label>
|
||||||
|
<textarea id="description" formControlName="description"></textarea>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<label for="image">Image URL:</label>
|
||||||
|
<input id="image" type="file" formControlName="image" (change)="onFileChange($event)">
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div formArrayName="ingredients">
|
||||||
|
<h3>Ingredients</h3>
|
||||||
|
<button type="button" (click)="addIngredient()">Add Ingredient</button>
|
||||||
|
<div *ngFor="let ingredient of ingredients.controls; let i = index" [formGroupName]="i">
|
||||||
|
<label for="ingredientName">Ingredient:</label>
|
||||||
|
<select id="ingredientName" formControlName="name">
|
||||||
|
<option *ngFor="let option of ingredientsOptions" [value]="option" [selected]="option === defaultOption">
|
||||||
|
{{option}}</option>
|
||||||
|
</select>
|
||||||
|
<label for="ingredientQuantity">Quantity:</label>
|
||||||
|
<input id="ingredientQuantity" formControlName="qty">
|
||||||
|
<button type="button" (click)="removeIngredient(i)">Remove</button>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Add Recipe</button>
|
||||||
|
</form>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecipeFormComponent } from './recipe-form.component';
|
||||||
|
|
||||||
|
describe('RecipeFormComponent', () => {
|
||||||
|
let component: RecipeFormComponent;
|
||||||
|
let fixture: ComponentFixture<RecipeFormComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [RecipeFormComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(RecipeFormComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,83 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { Recipe } from '../model/recipe.model';
|
||||||
|
import { Ingredient } from '../model/ingredient.model';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { RecipeService } from '../services/recipe.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-recipe-form',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './recipe-form.component.html',
|
||||||
|
styleUrls: ['./recipe-form.component.css']
|
||||||
|
})
|
||||||
|
|
||||||
|
export class RecipeFormComponent {
|
||||||
|
recipeForm: FormGroup;
|
||||||
|
base64Image: string | ArrayBuffer | null = null;
|
||||||
|
ingredientsOptions = ['Champignon', 'Tomata', 'Mozarella'];
|
||||||
|
defaultOption: string = this.ingredientsOptions[2];
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder, private recipeService: RecipeService) {
|
||||||
|
this.recipeForm = this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
description: ['', Validators.required],
|
||||||
|
image: ['', Validators.required],
|
||||||
|
ingredients: this.fb.array([]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get ingredients(): FormArray {
|
||||||
|
return this.recipeForm.get('ingredients') as FormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
addIngredient(): void {
|
||||||
|
this.ingredients.push(this.fb.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
qty: ['', Validators.required]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeIngredient(index: number): void {
|
||||||
|
this.ingredients.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFileChange(event: Event) {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
if (input.files && input.files[0]) {
|
||||||
|
const file = input.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
this.base64Image = reader.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.recipeForm.valid) {
|
||||||
|
const newRecipe: Recipe = {
|
||||||
|
id: 0,
|
||||||
|
name: this.recipeForm.value.name,
|
||||||
|
description: this.recipeForm.value.description,
|
||||||
|
image: this.base64Image?.toString() || "no-data",
|
||||||
|
ingredients: this.recipeForm.value.ingredients.map((ingredient: Ingredient, idx: number) => ({
|
||||||
|
id: idx,
|
||||||
|
name: ingredient.name,
|
||||||
|
qty: ingredient.qty,
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
console.log('Recipe added:', newRecipe);
|
||||||
|
this.recipeService.addRecipe(newRecipe);
|
||||||
|
this.recipeForm.reset();
|
||||||
|
} else {
|
||||||
|
console.log('Form is invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,31 @@
|
|||||||
import { Recipe } from "../model/recipe";
|
import { Injectable } from '@angular/core';
|
||||||
import { RECIPES } from "../datas/recipe.stub";
|
import { Recipe } from '../model/recipe.model';
|
||||||
import { Injectable } from "@angular/core";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
export class RecipeService {
|
export class RecipeService {
|
||||||
private recipes: Recipe[];
|
private localStorageKey = 'recipes';
|
||||||
|
private recipes: Recipe[] = [];
|
||||||
|
|
||||||
constructor(){
|
constructor() { }
|
||||||
this.recipes = RECIPES;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAll(): Recipe[]{
|
// Get recipes from local storage
|
||||||
return this.recipes;
|
getRecipes(): Recipe[] {
|
||||||
}
|
const recipesJson = localStorage.getItem(this.localStorageKey) || "[]";
|
||||||
|
this.recipes = JSON.parse(recipesJson) || [];
|
||||||
|
return this.recipes;
|
||||||
|
}
|
||||||
|
|
||||||
addRecipe(recipe: Recipe): void {
|
// Add a new recipe
|
||||||
this.recipes.push(recipe);
|
addRecipe(recipe: Recipe): void {
|
||||||
}
|
this.getRecipes();
|
||||||
|
this.recipes.push(recipe);
|
||||||
|
localStorage.setItem(this.localStorageKey, JSON.stringify(this.recipes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all recipes (for example, if needed)
|
||||||
|
clearRecipes(): void {
|
||||||
|
localStorage.removeItem(this.localStorageKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue