Note that the course project you're working with is inside your github folder, called 'first-angular-pro-udemy'.


44. Project Introduction

We will build a Recipe Book and a Shopping List app. We will manage them, be able to push from Recipe to Shopping List.

45. Planning The App

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)

46 + 47. Creating a New App Correctly

+ Setting up the Application

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.

48. Creating the Components

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.

49 + 50 + 51. Using the Components

+ Adding a Navigation Bar

+ Alternative Non-Callapsable Navigation Bar

Pratical sections.

52. Creating a "Recipe" Model

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.

53. Adding Content to the Recipes Components

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 just recipes: 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.

54. Outputting a List of Recipes wih ngFor

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:

https://imgur.com/cChlqCI

55. Displaying Recipe Details

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.

56. Working on the ShoppingListComponent

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>

57. Creating an "Ingredient" Model

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;
    }
}

Important Note:

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){}
}

58. Creating and Outputting the Shopping List

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>

59. Adding a Shopping List Edit Section

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.

60. Wrap Up & Next Steps

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).