Express JS - using template engine to generate an HTML response that contains a list of all objects stored on the server

I’m trying to learn express and create an application that will allow users to create new recipes, browse existing recipes, and view recipes.

I’ve got my server running by typing recipeserver.js in the cmd bar and then typing localhost:3000 in my address bar on google chrome. So far it loads the index.html homepage and from there which looks like this:

Screenshot (1)

From there I am able to browse a list of current recipes in the database (so far there are only 3 declared in the recipeserver.js file) and I am able to click on a link titled “Create a Recipe” which leads me to the create.html page that looks like this:

MyPage

The create.html page allows a user to enter recipe information. When the Save Recipe button is clicked, the addrecipe.js file is supposed to send the recipe data to the server using a POST request to the resource /recipes. Within the server code, all recipes will be stored in a single object called database. The keys of this object will be unique IDs and the values will be the recipes associated with those IDs.

I’m able to save any recipe I create but for some reason, all the recipes don’t appear on recipes.pug page when I click Browse Recipes. The first 3 recipes which were already included in the database object within the server code show up and their recipe links remain constant, and then the 4th recipe link is always replaced by the next recipe I create. Example of what the recipes.pug page looks like:

Screenshot

So for example if I had the 3 original recipes and I add a 4th recipe, a link for the 4th recipe appears. In the picture it’d be the ‘Braised Kangaroo with Potato’ recipe. But once I go on and add a 5th recipe, the 4th recipe ‘Braised Kangaroo with Potato’ would be gone and instead be replaced by a link for the 5th recipe which has a different name. In this case, there should be 5 recipes instead of 4, but the 4th link keeps getting constantly replaced by the newest recipe created. I want every recipe I add in addition to the 3 recipes that were already in database to appear in the list, but for some reason it just has the 3 original recipes and then the last link being continually updated with the most recent recipe I created. I have no idea why it’s doing that and would appreciate any help.

Additionally, the address for each of the recipes in the list should be localhost:3000/recipes/{recipeID}. The first 3 recipe links which were already in the database correctly have the addresses http://localhost:3000/recipes/0, http://localhost:3000/recipes/1, and http://localhost:3000/recipes/2, but for some reason the 4th link which would be the recipe I created has the link http://localhost:3000/recipes/undefined. Does anyone know why the id is undefined? In my server code I let the id = 3 as there are already 3 other recipes with ids 0, 1, and 2, and try to increment it every time a new recipe is added. I’m not sure why the ids for any newly created recipe is undefined.

Here’s all my code incase anyone wants to run it but I believe my problem just lies in the recipeserver.js file. When the Save Recipe button is clicked, the addrecipe.js file sends the recipe data to the server using a POST request to the resource /recipes.

recipeserver.js:

const express = require('express');
const fs = require("fs");
const shortId = require("short-id");
const session = require('express-session');
const app = express();
const pug = require("pug");
const port = 3000;


let database = {
    "0":{
        "ingredients":
        [
            {"name":"Crab","unit":"Tsp","amount":3},
            {"name":"Peas","unit":"Cup","amount":12},
            {"name":"Basil","unit":"Tbsp","amount":10},
            {"name":"Cumin","unit":"Liter","amount":3},
            {"name":"Salt","unit":"Tbsp","amount":1}
        ],

        "name":"Boiled Crab with Peas",
        "preptime":"13",
        "cooktime":"78",
        "description":"A boring recipe using Crab and Peas",
        "id":"0"
    },
    "1":{
        "ingredients":
        [
            {"name":"Peanuts","unit":"Liter","amount":10},
            {"name":"Artichoke","unit":"Tsp","amount":3},
            {"name":"Basil","unit":"Cup","amount":11},
            {"name":"Sage","unit":"Grams","amount":13},
            {"name":"Pepper","unit":"Cup","amount":1}
        ],

        "name":"Boiled Peanuts with Artichoke",
        "preptime":"73",
        "cooktime":"74",
        "description":"A exciting recipe using Peanuts and Artichoke",
        "id":"1"
    },
    "2":{
        "ingredients":
        [
            {"name":"Lobster","unit":"Tsp","amount":14},
            {"name":"Brussel Sprouts","unit":"Liter","amount":14},
            {"name":"Sage","unit":"Tbsp","amount":3},
            {"name":"Thyme","unit":"Tbsp","amount":12},
            {"name":"Pepper","unit":"Tsp","amount":10},
            {"name":"Cumin","unit":"Tbsp","amount":11}
        ],

        "name":"Spicy Lobster with Brussel Sprouts",
        "preptime":"86",
        "cooktime":"19",
        "description":"A tasty recipe using Lobster and Brussel Sprouts",
        "id":"2"
    }
}


let recipes = {};

for (let recipe in database) {
  recipes[recipe.id] = recipe;
};

app.set("view engine", "pug");
app.use(express.static("public"));
app.use(express.json());
app.use(express.urlencoded({extended: true}));

app.get("/addrecipe.js", getAddRecipeJS);
app.get("/recipes", loadRecipes);
app.get("/recipe", loadRecipe);
app.route("/recipes", loadRecipes);
app.post('/recipes', saveRecipes);

let id = 3;
function loadRecipes(request, response, next){
      response
        .status(200)
        .render('recipes.pug', { session: request.session, recipes: database });
      id++;
     
}

function saveRecipes(request, response, next) {
   console.log(request.body);
   id++;
   const dbLength = Object.keys(database).length;
   database.dbLength = request.body;
   response.send('Success');
}

function loadRecipe(req, res, next){
    res.status(200).render("recipe.pug", {"session": req.session});
}

function getAddRecipeJS(req, res, next){
    fs.readFile("addrecipe.js", function(err, data){
        if(err){
            res.statusCode = 500;
            res.end("Error reading file.");
            return;
        }
        res.status(200).send(data);
        return;
    });
}

app.listen(port);
console.log(`Server listening at http://localhost:${port}`);

index.html:

<html>

	<head><title>Recipe App Home Page</title></head>
	
	<body>
		<h1>Welcome to the Recipe App</h1>
		<br>
		<a href="/create.html">Create a Recipe</a><br>
		<a href="/recipes">Browse Recipes</a><br>		
	</body>
</html>

create.html:

<html>
	<head><title>Create a Recipe</title></head>
	
	<body>
		<script src="/js/addrecipe.js"></script>
		
		<button type="button" onclick="genRandom()">Generate Random Recipe Data</button>
		<button type="button" onclick="submit()">Save Recipe</button>
		<br><br>
		
		Recipe Name: <input type="textbox" id="recipename" size="50"><br>
		
		Prep Time: <input type="textbox" id="preptime" size="50"><br>
		
		Cook Time: <input type="textbox" id="cooktime" size="50"><br>
		
		Description: <textarea rows="5" cols="50" id="description"></textarea><br><br>
		
		Add ingredients:<br>
		Unit: <select id="unit">
		<option value="Tsp">Teaspoon</option>
		<option value="Tbsp">Tbsp</option>
		<option value="Cup">Cup</option>
		<option value="Liter">Liter</option>
		<option value="Gram">Gram</option>
		</select><br>
		
		Amount: <input type="textbox" id="amount"><br>
		
		Ingredient: <input type="textbox" id="ingredient"><br>
		
		<button type="button" id="add" onclick="addIngredient()">Add Ingredient</button>
		<br><br>
		<div id="ingredients">
		
		</div><br>
		<button type="button" id="submit" onclick="submit()">Save Recipe</button>
	</body>
</html>

addrecipe.js:

let descriptors = ["Sweet", "Spicy", "BBQ", "Braised", "Deconstructed", "Broiled", "Boiled", "Flambeed", "Raw", "Smoked", "Butterflied", "Cured", "Grilled", "Poached"];
let proteins = ["Chicken", "Beef", "Lobster", "Shrimp", "Crab", "Turkey", "Duck", "Tofu", "Chickpeas", "Lentils", "Peanuts", "Kangaroo", "Human", "Goose", "Fish", "Pork", "Eggs", "Deer"];
let accompany = ["Broccoli", "Carrots", "Peas", "Potato", "Kale", "Banana", "Artichoke", "Asparagus", "Beans", "Broccoli", "Brussel Sprouts", "Celery", "Melon", "Mushrooms", "Pumpkin"];
let spices = ["Salt", "Pepper", "Basil", "Thyme", "Sage", "Cumin"];
let mealDescriptors = ["tasty", "mediocre", "very good", "boring", "exciting", "delicious", "easy", "ridiculously complex"];
let units = ["Tbsp", "Tsp", "Cup", "Liter", "Grams"]

let recipe = {ingredients: []};

function addIngredient(){
	let name = document.getElementById("ingredient").value;
	let amount = document.getElementById("amount").value;
	let unit = document.getElementById("unit").value;
	let ingredient = {name, amount, unit};
	recipe.ingredients.push(ingredient);
	updateIngredients();
}

function updateIngredients(){
	let innerHTML = "";
	recipe.ingredients.forEach(ingredient => {
		innerHTML += ingredient.amount + " " + ingredient.unit + " " + ingredient.name + "<br>";
	});
	document.getElementById("ingredients").innerHTML = innerHTML;
}

function submit(){
	recipe.name = document.getElementById("recipename").value;
	recipe.preptime = document.getElementById("preptime").value;
	recipe.cooktime = document.getElementById("cooktime").value;
	recipe.description = document.getElementById("description").value;
	
	let req = new XMLHttpRequest();
	req.onreadystatechange = function() {
		if(this.readyState==4 && this.status==200){
			alert("recipe saved");
		}
	}
	
	//Send a POST request to the server containing the recipe data
	req.open("POST", `/recipes`);
	req.setRequestHeader("Content-Type", "application/json");
	req.send(JSON.stringify(recipe));
}

recipes.pug:

html
	head
		title Recipes
body
	a(href="/create.html") add a recipe
	div#main
		h1 List of Recipes:
		each recipe in recipes
			a(href="/recipes/" + recipe.id) #{recipe.name}
			br

recipe.pug:

html
	head
		title #{recipe.name}
body

	div#main
		h1 #{recipe.name}
		br

I run the code by typing node recipeserver.js in my cmd bar and then going to localhost:3000 in my google chrome browser.