Building a Food Recipe Web App

Using HTML, CSS and Javascript

Building a Food Recipe Web App

In this article, we would create a functional application that allows individuals search for food recipes. To get these recipes, we have to make use of an external API.

API is the acronym for Application Programming Interface. It is a collection of programming code that allows data to be exchanged from one software product to another.

You use an API every time you use an application like Twitter, WhatsApp, or the weather forecast app on your device.The API functions as an intermediary between the user’s web page/ application and the web server. When you make an API call, a request is made to the server and you will receive an appropriate response.

20210521_003524_0000.png

There are several food recipes out there, however in this article we would use the Edamam API. You can check out the documentation here

Let us state out the functionalities of this recipe app. They include:

  1. App should use an input to take in recipe to search for.
  2. Recipes must be mapped to
  3. There should be a link to the full recipes
  4. App should show image for the food recipe Now lets delve right into building our application

SIGN UP

We have to sign up to the developer account on the Edamam website in order to have access to our app key and app id. These are credentials which would be very important when we want to make an http request.

e1.PNG

e2.PNG

HTML SetUp

We would create a nav section that houses our logo and the a tags for page navigation. An input tag and a button tag with classes which would come handy during our page styling with CSS and DOM Manipulation with JavaScript.

An empty div is created which would hold our data fetched. We also create multiple images and details in the main section on the page. A footer section that has an email signup for newsletter subscription. That pretty much makes up our landing HTML page.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Food Recipes</title>
</head>
<body>
 <!-- Page Navigation-->
    <nav>
        <a href="#">Noire Recipes</a>
        <ul>
            <li><a href="index.html">Home</a></li>
            <li><a href="#main-two">Blog</a></li>
            <li><a href="#footer">Contact Us</a></li>    
        </ul>
    </nav>
 <!-- Input and Button Section-->
    <div class="recipe-search">
            <input type="text" class="recipe" placeholder="Find a Recipe....">
            <button class="button">SEARCH</button>    
    </div>
    <div id="header">
        <p >Search By Name</p>
    </div>
<!-- Search Results for recipe-->
    <div class="food-class">

    </div>
<!-- Other Details for Recipe-->
    <main>
        <div class="row">
            <div class="col border-red lg-image">
                <img src="images/3.jpg" alt="food-image">
                <h1>15 Greek Grilled Chicken Recipes</h1>
                <p>Looking for a crowd-pleasing recipe to make on the grill? Your search ends here: these Greek-inspired grilled chicken dishes are sure to satisfy everyone at your dinner table</p>
            </div>
            <div class="col border-red">
                <h2>Most Popular</h2>
                <div class="popular-section">
                    <img src="images/4.jpg" alt="food-image">
                    <p>Camping Recipes</p>
                </div>
                <div class="popular-section">
                    <img src="images/6.jpg" alt="food-image">
                    <p>100+ Banana Bread Recipes</p>
                </div>
                <div class="popular-section">
                    <img src="images/7.jpg" alt="food-image">
                    <p>What to Make to Celebrate Every Food Holiday in May</p>
                </div>
                <div class="popular-section">
                    <img src="images/8.jpg" alt="food-image">
                    <p>9 Pizza Mashups That Are Pure Cheesy Brilliance</p>
                </div>
            </div>
        </div>

    </main>
<!-- Blog Section for recipe-->
    <main class="main-two" id="main-two">
        <h2>The New Guide to Wedding Dishes</h2>
        <p class="text-center">2021 will be a big year for weddings—and you’ve got to be prepared, whether you’re the couple creating the registry or the repeat wedding guest who will have to manage buying so many gifts. Here's all of our advice.</p>
        <div class="row blog-section">
            <div class="col ">
                <img src="images/9.jpg" alt="food-image">
                <p>No more dry, lackluster burgers. These are juicy, and spices can be easily added 
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/janewoolabver@accesswave.ca/"> By Jane</a></span></p>
            </div>
            <div class="col">
                <img src="images/10.jpg" alt="food-image">
                <p>This recipe is from my mother. It may sound strange, but these are really good and very easy to make...
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/788781/">By JAQATAC</a></span></p>
            </div>
            <div class="col">
                <img src="images/11.jpg" alt="food-image">
                <p>These salmon patties are delicious for lunch or dinner.
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/Sue%C2%BBSue/">By Sue</a></span></p>
            </div>
            <div class="col">
                <img src="images/12.jpg" alt="food-image">
                <p>You might think this was invented to avoid all of that time-consuming wrapping 
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/foodwisheswithchefjohn/">By Chef John</a></span></p>
            </div>
            <div class="col">
                <img src="images/13.jpg" alt="food-image">
                <p>This basic chicken salad is a family favorite. I like to use baked thighs...
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/jmateyka@pacbell.net/">By Jackie M.</a></span></p>
            </div>
            <div class="col">
                <img src="images/1.jpg" alt="food-image">
                <p>Pan fried chicken cubes served with a sweet and sour sauce.
                    <span><a target="_blank" href="https://www.allrecipes.com/cook/447155/">By Lindahue</a></span></p>
            </div>    
        </div>
    </main>
<!-- Footer-->
    <footer id="footer">
        <h4>Get on the latest recipes and expert tips right in your inbox</h4>
        <div class="newsletter">
            <input type="text" class="address" placeholder="Your email address">
            <button class="signup">SIGN UP</button>
        </div>
        <div class="social-media">
            <ul>
                <li><a href="#">Facebook</a></li>
                <li><a href="#">Twitter</a></li>
                <li><a href="#">Instagram</a></li>
            </ul>
        </div>
        <div class="love-span">
            <small>Made with <span></span> by Marienoir</small>
        </div>
    </footer>
    <script src="script.js"></script>
</body>
</html>

CSS Styling

To make our page more appealing and beautiful, we add some basic stylings to the HTML page. Do not forget to add the link the CSS file to the HTML file created above using the link tag.

/* GENERAL STYLING */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;500;700&display=swap');
*{
    padding: 0;
    margin: 0;
}
body{
    box-sizing: border-box;
    font-size: 12px;
    background-color: rgb(230, 224, 216);
    color: rgb(31, 30, 30);
    font-family: 'Poppins', sans-serif;
    font-weight: 300;
}
/* NAVIGATION STYLING */
nav{
    background-color: rgb(214, 14, 14);
    display: flex;
    justify-content: space-between;
    padding: 20px;
}
nav ul{
    list-style-type: none;

}
nav ul li{
    display: inline;
    margin-left: 20px;
}
nav a{
    text-decoration: none;
    color: white;
}
/* SEARCH INPUT STYLING */
.recipe-search{
    display: flex;
    justify-content: center;
    margin-top: 50px;
}
.recipe,
.address {
    padding: 15px;
    border: none;
}
.button {
    padding: 10px;
    background: rgb(214, 14, 14);
    color: white;
    border: none;
}
.button:hover{
    background-color:rgb(245, 66, 66) ;
}
/* HEADER STYLING */
#header{
    width: 100%;
    height: 50%;
    text-align: center;
    font-size: 18px;
    position: relative;
    background-color: rgb(230, 224, 216);
    margin-top: 20px;
    margin-bottom: 30px;
}
#header::after{
    content: "";
    width: 100%;
    border-bottom: 1px solid red;
    position: absolute;
    left: 0;
    top: 50%;
    z-index: 1;
}
#header p{
    background-color: rgb(230, 224, 216);
    width: auto;
    display: inline-block;
    z-index: 3;
    padding: 0 20px 0 20px;
    color: black;
    position: relative;
    margin: 0;
}
/* OTHER DETAILS STYLING */
.lg-image img{
    height: 300px;
    width: 350px;
}
.popular-section {
    display: flex;
    align-items: center;
}
.popular-section img{
    height: 100px;
    width: 100px;
    margin-bottom: 20px;
}
.popular-section p{
    padding: 10px;
}
 h2{
    text-align: center;
    padding: 20px;
    font-size: 25px;
}
.main-two {
    padding: 20px;
    color: black;
    border-top: 3px solid red;
    background-repeat: no-repeat;
    background-size: cover;
}
.main-two p{
    text-align: justify;
}
.text-center {
    text-align: center;
    padding:5px 20px;
}

.main-two span{
        display: block;
}
.main-two span a{
    color: rgb(209, 43, 43);
}
.blog-section p{
    color: black;
}
/* FOOD CLASS STYLING */
.food-recipe {
    background: rgb(230, 224, 216);
    display: flex;
    border-bottom: 2px solid red;
    margin-bottom: 20px;
}
.food-img{
    margin: 10px;
}
.food-img img{
    width: 100px;
    height: 100px;
}
.food-details{
    padding: 10px;
}
.food-details a{
    text-decoration: none;
    color: red;
    margin-top: 20px;
}
.border-red{
    background-color: white;
}

/* FOOTER STYLING */
footer{
    background-color: rgb(233, 22, 22);
    height: 210px;
}
.newsletter{
    display: flex;
    justify-content: center;
    margin-top: 10px;
}
.signup {
    padding: 10px;
    background: black;
    color: white;
    border: none;
}
h4,
.love-span{
    text-align: center;
    font-size: 15px;
    padding-top: 20px;
    color: rgb(255, 254, 254);
}
.social-media{
    display: flex;
    justify-content: center;
    margin-top: 12px;
}
.social-media ul{
    list-style-type: none;
}
.social-media ul li{
    display: inline-block;
    font-size: 12px;
    text-decoration: underline;
}
.social-media a{
    text-decoration: none;
    color: white;
}
.social-media a:hover,
nav a:hover{
    color: rgb(240, 155, 155);
}
.love-span span{
    color: rgb(255, 255, 255);
}
/* FLEX GRID STYLING */
.row{
   max-width: 1200px;
   margin: 0 auto;
   display: grid;
   grid-gap:1rem;  
}
.col{
    border-radius: 5px;
    color: black;
    padding: 1rem;
}
.col h1{
    font-size: 19px;
}
.col p{
    margin-bottom: 20px;
    font-size: 15px;
}
.col img{
    height: 200px;
    width: 250px;
    border: 2px solid gray;
    border-radius: 7px; 
}
/* MEDIA QUERIES */
@media (min-width:600px){
    .row{
        grid-template-columns: repeat(2,1fr);
    }
}
@media (min-width:900px){
    .row{
        grid-template-columns: repeat(2,1fr);
    }

}

JavaScript Manipulation

This is where the real fun begins. We would do this together, a step at a time. We would select the ‘button’ and the ‘recipe’ class and save them to a variable ‘button’ and ‘recipeText’ respectively.

const button = document.querySelector(".button");
const recipeText = document.querySelector(".recipe");

Using the ‘addEventListener()' method, we would listen for a ‘click’ and then execute a function. In this case, when the search button is clicked, it fetches the API .This can be easily achieved using Fetch or Axios. Fetch and Axios are very similar in functionality. You can read this article to know more about the differences between Fetch and Axios. However for the sake of this article, we would use the fetch method.

    const recipe =recipeText.value;
    fetch(`https://api.edamam.com/search?q=${recipe}&app_id=Your_App_Id&app_key=Your_App_Key&from=0&to=10&calories=591-722&health=alcohol-free`)

I pass the URL to fetch and set the .then() callback to console the data that gets returned from the request.

.then(response=>{
        console.log(response);
        if(!response.ok){
          throw Error("Error");
        }
          return response.json();
        })

r1.PNG

That’s great, but the first response is not the data we are looking for. That is the response from the server letting us know that our request went through just fine. Great, but you can’t do much with that. To get to that data, you have to pass it to .json() first and then you can see it.

r2.PNG

Now, this is the data from Edamam that we wanted. Looking closely at the data gotten, we can see that it is an object and in accessing the values of a JavaScript object we use the dot notation. The values we need are enclosed in the key ‘hits’. We would use the map() method to iterate and modify its elements using a callback function. The element argument in the map method is named ‘food’ , feel free to give any name of your choice. The callback function will then be executed on each of the array's elements. For each of the elements, the block of code in the return is executed. In the return block, we are accessing the ‘recipe’ key of every ‘food’ elements. In the ‘recipe’ , we have numerous keys but for our project we need just the ‘image’ , ‘label’, ‘ingredientLines’ and ‘url’.

r3.PNG

.then(data =>{
            console.log(data.hits);
            const html = data.hits.map(food =>{
              return`
                <div class="food-recipe">
                  <div class="food-img">
                    <img src=${food.recipe.image} alt="" />
                  </div>
                  <div class="food-details">
                    <h3> ${food.recipe.label}</h3>
                    <p>Ingredients include ${food.recipe.ingredientLines}</p>
                    <a href="${food.recipe.url}" target="_blank">Full Recipe Here... </a>   
                  </div>    
              </div>`;
            }).join("");

The map() process is saved to a variable ‘html’.

 console.log(html);
            document.querySelector(".food-class").insertAdjacentHTML("afterbegin", html);
      })
    .catch(err => console.log(err))
})

We can console the html to be certain it works. Now we reflect this to our browser by using the querySelector on the class ‘food-class’ . In the event of an error, the .catch method takes this and then log out the error in the console. Our js file should look like this.

const button = document.querySelector(".button");
const recipeText = document.querySelector(".recipe");
button.addEventListener("click",()=>{
    const recipe =recipeText.value;
    fetch(`https://api.edamam.com/search?q=${recipe}&app_id=76e268d1&app_key=5bc5c2506d79110b59a7d56c511f24c3&from=0&to=10&calories=591-722&health=alcohol-free`)
    .then(response=>{
        console.log(response);
        if(!response.ok){
          throw Error("Error");
        }
          return response.json();
        })
        .then(data =>{
            console.log(data.hits);
            const html = data.hits.map(food =>{
              return`
                <div class="food-recipe">
                  <div class="food-img">
                    <img src=${food.recipe.image} alt="" />
                  </div>
                  <div class="food-details">
                    <h3> ${food.recipe.label}</h3>
                    <p>Ingredients include ${food.recipe.ingredientLines}</p>
                    <a href="${food.recipe.url}" target="_blank">Full Recipe Here... </a>   
                  </div>    
              </div>`;
            }).join("");
            console.log(html);
            document.querySelector(".food-class").insertAdjacentHTML("afterbegin", html);
      })
    .catch(err => console.log(err))
})

With these steps, we have successfully built our Food Recipe App using HTML, CSS and JavaScript. You can check out our app HERE

i1.PNG

If you found this article helpful, please feel free to leave your comments and questions too. I would be glad to answer them.

You can also share your version of the app with me on Twitter 🙂

Happy Coding 💛💛💛!!!!

RESOURCES