Hacking away at signals and resources.
This commit is contained in:
parent
ab1c39560f
commit
86ef321065
@ -1,5 +1,4 @@
|
|||||||
<main>
|
<main>
|
||||||
<app-recipe></app-recipe>
|
<h1>Meals Made Easy</h1>
|
||||||
|
<router-outlet />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<router-outlet />
|
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
|
import { RecipeView } from './recipe-view/recipe-view.component';
|
||||||
|
|
||||||
export const routes: Routes = [];
|
export const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: 'recipes/:username/:slug',
|
||||||
|
component: RecipeView
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { Component, signal } from '@angular/core';
|
import { Component, signal } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { Recipe } from './recipe/recipe';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [RouterOutlet, Recipe],
|
imports: [RouterOutlet],
|
||||||
templateUrl: './app.html',
|
templateUrl: './app.html',
|
||||||
styleUrl: './app.css',
|
styleUrl: './app.css',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -6,7 +6,20 @@ export interface RecipeInfoViews {
|
|||||||
content: Recipe[];
|
content: Recipe[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RecipeView {
|
||||||
|
isOwner: boolean | null;
|
||||||
|
isStarred: boolean | null;
|
||||||
|
recipe: Recipe;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Recipe {
|
export interface Recipe {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
mainImage: ImageView;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageView {
|
||||||
|
alt: string;
|
||||||
|
url: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
<h1>{{ recipe.title }}</h1>
|
||||||
|
<img [ngSrc]="recipe.mainImage.url" [alt]="recipe.mainImage.alt" [width]="600" [height]="400">
|
||||||
|
<div [innerHTML]="recipe.text"></div>
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecipeViewCard } from './recipe-view-card.component';
|
||||||
|
|
||||||
|
describe('Card', () => {
|
||||||
|
let component: RecipeViewCard;
|
||||||
|
let fixture: ComponentFixture<RecipeViewCard>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [RecipeViewCard]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(RecipeViewCard);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Recipe } from '../../model/Recipe.model';
|
||||||
|
import { NgOptimizedImage } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-recipe-view-card',
|
||||||
|
imports: [
|
||||||
|
NgOptimizedImage
|
||||||
|
],
|
||||||
|
templateUrl: './recipe-view-card.component.html',
|
||||||
|
styleUrl: './recipe-view-card.component.css',
|
||||||
|
})
|
||||||
|
export class RecipeViewCard {
|
||||||
|
|
||||||
|
@Input({ required: true })
|
||||||
|
public recipe!: Recipe;
|
||||||
|
|
||||||
|
}
|
||||||
0
src/app/recipe-view/recipe-view.component.css
Normal file
0
src/app/recipe-view/recipe-view.component.css
Normal file
5
src/app/recipe-view/recipe-view.component.html
Normal file
5
src/app/recipe-view/recipe-view.component.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@if (recipe.isLoading()) {
|
||||||
|
<p>Loading...</p>
|
||||||
|
} @else if (recipe.hasValue()) {
|
||||||
|
<app-recipe-view-card [recipe]="recipe.value()"></app-recipe-view-card>
|
||||||
|
}
|
||||||
@ -1,17 +1,17 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { Recipe } from './recipe';
|
import { RecipeView } from './recipe-view.component';
|
||||||
|
|
||||||
describe('Recipe', () => {
|
describe('Recipe', () => {
|
||||||
let component: Recipe;
|
let component: RecipeView;
|
||||||
let fixture: ComponentFixture<Recipe>;
|
let fixture: ComponentFixture<RecipeView>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [Recipe],
|
imports: [RecipeView],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(Recipe);
|
fixture = TestBed.createComponent(RecipeView);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
25
src/app/recipe-view/recipe-view.component.ts
Normal file
25
src/app/recipe-view/recipe-view.component.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Component, inject, resource } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { RecipeService } from '../recipe.service';
|
||||||
|
import { RecipeViewCard } from './recipe-view-card/recipe-view-card.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-recipe-view',
|
||||||
|
imports: [
|
||||||
|
RecipeViewCard
|
||||||
|
],
|
||||||
|
templateUrl: './recipe-view.component.html',
|
||||||
|
styleUrl: './recipe-view.component.css',
|
||||||
|
})
|
||||||
|
export class RecipeView {
|
||||||
|
private recipeService = inject(RecipeService);
|
||||||
|
private route = inject(ActivatedRoute);
|
||||||
|
private username = this.route.snapshot.paramMap.get('username') as string;
|
||||||
|
private slug = this.route.snapshot.paramMap.get('slug') as string;
|
||||||
|
|
||||||
|
protected recipe = resource({
|
||||||
|
loader: () => {
|
||||||
|
return this.recipeService.getRecipe(this.username, this.slug);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
import { Recipe, RecipeInfoViews } from './model/Recipe.model';
|
import { Recipe, RecipeInfoViews, RecipeView } from './model/Recipe.model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@ -14,4 +14,10 @@ export class RecipeService {
|
|||||||
.get<RecipeInfoViews>('http://localhost:8080/recipes')
|
.get<RecipeInfoViews>('http://localhost:8080/recipes')
|
||||||
.pipe(map((res) => res.content));
|
.pipe(map((res) => res.content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getRecipe(username: string, slug: string): Promise<Recipe> {
|
||||||
|
const res = await fetch(`http://localhost:8080/recipes/${username}/${slug}`)
|
||||||
|
const recipeView = await res.json() as RecipeView;
|
||||||
|
return recipeView.recipe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
<p>recipe works!</p>
|
|
||||||
<p>{{ title() }}</p>
|
|
||||||
@for (recipeTitle of recipeTitles(); track recipeTitle) {
|
|
||||||
<p>{{ recipeTitle }}</p>
|
|
||||||
}
|
|
||||||
<button (click)="onClick()">Click me!</button>
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
import { Component, inject, signal } from '@angular/core';
|
|
||||||
import { RecipeService } from '../recipe.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-recipe',
|
|
||||||
imports: [],
|
|
||||||
templateUrl: './recipe.html',
|
|
||||||
styleUrl: './recipe.css',
|
|
||||||
})
|
|
||||||
export class Recipe {
|
|
||||||
protected readonly title = signal('Hello, Jesse!');
|
|
||||||
protected readonly recipeTitles = signal<string[]>([]);
|
|
||||||
|
|
||||||
private readonly recipeService = inject(RecipeService);
|
|
||||||
|
|
||||||
protected onClick() {
|
|
||||||
this.recipeService.getRecipes().subscribe((recipes) => {
|
|
||||||
this.recipeTitles.set(recipes.map((recipe) => recipe.title));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user