Note that the course project you're working with is inside your github folder, called 'first-angular-pro-udemy'.
We will build a Recipe Book and a Shopping List app. We will manage them, be able to push from Recipe to Shopping List.
Planning the structure of the app, thinking about the components we would need. Naturally, during building, we will end up adding some components that we didn't plan or merging components we thought would be separte. Still, it is a good idea to plan components ahead of time.
The components we 'planned' for this app are:
Under Shooping List (Wrapper) Component:
Under Recipe Book (Wrapper) Component:
We will also add other components later on. Also look at the visual map he created, and how he thought of features, components, and model (data)
Similar to what we did earlier. Run the ng-command
with --no-strict
flag, install bootstrap (version 3 -?) and add it to the angular.json file.
Go over the components and create them.
Keep in mind that it is good to structure things, and than you can create a new component inside another component.
To create a new component recipe-list
inside another component called recipes
, just follow the follow the following command:
ng g c recipes/recipe-list
We have multilevel hirearchies, for example, recipe-list
went under recipes
, and recipe-item
went under recipe-list
:
ng g c recipes/recipe-list/recipe-item
Note how all components are created with relation to root, and that you have to specify paths for components in the hirearchy.
Pratical sections.
Rcipes are something that we will use again and again within the app. This means we want to define how it looks [and what information it should always contain].
For that, we will create something called a Model
(Model not Modal ya zakzak). We will define it inside the Recipes Folder (not recipe-list or whatever).
We will call it: recipe.modal.ts
Inside it, we will use a js class. We don't need to import special stuff for this file, it is just here to define what kind of data does a recipe contain.
Here is what we put inside recipe.modal.ts:
export class recipe{
public name: string;
public description: string;
public imagePath: string;
constructor(name: string, desc: string, imagePath: string){
this.name = name;
this.description = desc;
this.imagePath = imagePath;
}
}
Defining a Modal seems like creating a new type: now I can have a piece of information that is of type Recipes (just like Structures in C).
In the next lecture we will see how it will be used.
Go to recipe-list.ts file, and create a recipes
array that is empty.
However, I want the array to be of type Recipe. So we import the Recipe
Modal from our file:
import { Component, OnInit } from '@angular/core';
import {Recipe} from '../recipe.modal'
@Component({
selector: 'app-recipe-list',
templateUrl: './recipe-list.component.html',
styleUrls: ['./recipe-list.component.css']
})
export class RecipeListComponent implements OnInit {
recipes: Recipe[] = [];
constructor() { }
ngOnInit(): void {
}
}
TS note: note that we wanted to declare an array of receipes, not just one recipe. That's why we used
recipes: Recipe[] = [];
instead of justrecipes: Recipe = [];
Now that we've imported it, we can use it to create instances of Recipes by calling the construction of the modal with the proper arguments.
Here, we are creating and adding a new recipe to the array:
//...
export class RecipeListComponent implements OnInit {
recipes: Recipe[] = [
new Recipe('Chocolate Cake', 'Delicious Chocoalte Cake', 'https://picsum.photos/200/300')
];
constructor() { }
ngOnInit(): void {
}
}
Now we will try to show it inside the recipe-list.html.
Now that we have an array (with one element, but whatever), we will use ngFor to output that element inside the html:
recipe-list.component.html
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success">New Recipe</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<a href="#" class="list-group-item clearfix" *ngFor='let recipe of recipes'>
<div class="pull-left">
<h4 class="list-group-item-heading">{{recipe.name}}</h4>
<p class="list-group-item-text">{{recipe.description}}</p>
</div>
<span class="pull-right">
<!-- <img src="{{recipe.imagePath}}" alt="{{recipe.name}}" class="img-responsive" style='max-height: 50px;'> -->
<img [src]="recipe.imagePath" alt="{{recipe.name}}" class="img-responsive" style='max-height: 50px;'>
</span>
</a>
<app-recipe-item></app-recipe-item>
</div>
</div>
Note how for the image, we could have used a second option for the
src
tag. We used property binding ([src] expects a string) - but since it expects a string, we could have also used string interpolation here.
If you now add another item to the recipes array, you will see it duplicated in the ui. Here is how the UI looks more or less:
Go to recipe-detail.component.html and edit is as such:
<div class="row">
<div class="col-xs-12">
<img src="" alt="" class="img-responsive">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<h1>Receipe Name</h1>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="btn-group">
<button class="btn-primary dropdown-toggle">
Manage Recipe <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#">To Shopping List</a></li>
<li><a href="#">Edit Recipe</a></li>
<li><a href="#">Delete Recipe</a></li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
Description
</div>
</div>
<div class="row">
<div class="col-xs-12">
Ingredients
</div>
</div>
In short, we created a detail element. We have a dropdown inside it with possible options.
We edited our shopping-list.component.html as such:
<div class="row">
<div class="col-xs-10">
<app-shopping-edit></app-shopping-edit>
<hr>
<ul class="list-group">
<a class="list-group-item" style="cursor: pointer"></a>
</ul>
</div>
</div>
We will be using Ingredients a lost throughout the app, that's why it makes sense to add an ingredient modal.
Note that earlier, we put the recipe modal in the recipes folder because it made sense. But now where to store the ingredients folder?
We will created a folder called 'shared' [inside the app folder] that will contain things used by many different other components (hence the name = shared).
Inside it, created ingredient.modal.ts
Now create the modal for Ingredient as such:
export class Ingredient{
public name: string;
public amount: number;
constructor(name: string, amount: number){
this.name = name;
this.amount = amount;
}
}
Since the above 'setup' is such a common way (declaring the properties then using them inside the constructor, etc), there is a shorthand way of doing the above, which is simply:
export class Ingredient{
constructor(public name: string, public amount: number){}
}
Now we will use the previous Modal inside shopping-list.component.ts
We will import the ingredient modal and create an ingredients
array using the modal:
import { Component, OnInit } from '@angular/core';
import { Ingredient } from '../shared/ingredient.modal'
@Component({
selector: 'app-shopping-list',
templateUrl: './shopping-list.component.html',
styleUrls: ['./shopping-list.component.css']
})
export class ShoppingListComponent implements OnInit {
ingredients: Ingredient[] = [
new Ingredient('Apples', 5),
new Ingredient('Tomatoes', 10),
]
constructor() { }
ngOnInit(): void {
}
}
Now go to shopping-list.component.html and use ngFor to loop through the ingredients
array and output the elements as: name (ammount)
<div class="row">
<div class="col-xs-10">
<app-shopping-edit></app-shopping-edit>
<hr>
<ul class="list-group">
<a
class="list-group-item"
style="cursor: pointer"
*ngFor = "let ingredient of ingredients"
>
{{ingredient.name}} ({{ingredient.amount}})
</a>
</ul>
</div>
</div>
Go to shopping-edit-component.html and:
<div class="row">
<div class="col-xs-12">
<div class="row">
<div class="col-sm-5 form-group">
<label for="name">Name</label>
<input type="text" id="name" class="form-control">
</div>
<div class="col-sm-2 form-group">
<label for="amount">Amount</label>
<input type="number" id="amount" class="form-control">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success" type="submit">Add</button>
<button class="btn btn-danger" type="button">Delete</button>
<button class="btn btn-primary" type="submit">Clear</button>
</div>
</div>
</div>
</div>
This is it.
We know have everything on the same page. Later on I would want to devide them.
We also want the components to be able to communicate with each other. (Seleted a listed recipe and have its details show up and so on).