Clean Out Yer Fridge
Published: 2022-09-16 23:19:25

Lunch, for many people, such as myself, is breakfast. So by the time lunchtime arrives, the last thing I want is to plan an elaborate meal in addition to making it, eating it, and cleaning up its wake. I’m hungry, and I know I’ll end up preparing, under the obstinate force of my habit, something I’ve made before. That’s fine, I like my repertoire, but I also like to explore and adventure and learn new things, so another uninspired panino feels hackneyed, a wasted opportunity. What to do? If only I could outsource the decision (and the preparation, but I’m not quite there yet) to someone else! If only I could be offered some suggestions for dishes I could make with what I already have?

This is the sort of thought process which absolutely did not lead me to create the Recipe Idea Generator web app, though it is a nice retrospective explication. For an app should have real utility—that’s the most important thing—in the end it’s a tool, not a jewel. But as a first project, the culmination of our twee first phase and therefore an embodiment of its curriculum, scope was the priority. What can we do with what we have and what we know? In truth, we looked through those free APIs whose functionality we could understand and fashioned our idea around one that seemed manageable. 

Nonetheless, it had all the characteristics of a good idea: it seemed feasible, useful, scalable, reasonably challenging, possibly original, fun. The little thing will give you recipe ideas, random if you like, or ones incorporating a couple of ingredients you already have. So we mustered the sort of enthusiasm which you find most concentrated at the beginning of an undertaking and tackled the main part right away.

The first step was figuring out how to obtain the information from the API–—basically, figuring out how the API worked. It seems they offered a few methods for our convenience. There was a simple way to fetch a random meal (and its corollary metadata: picture of the finished dish, ingredients, instructions, et cetera); there was a meal lookup by a meal “ID”; filter by ingredients; list of some ten latest additions. Once we realized the data we wanted was all available on the other side of these links, we needed only to call the fetch() method on each of these URLs to have the API yield its treasures to us. 

```
fetch(`https://www.themealdb.com/api/json/v2/9973533/lookup.php?i=${id}`)
```

We began with a loadRandom() function to fetch a random meal and populate the webpage with the relevant properties of that meal: namely, picture, name, instructions, and ingredients. This was relatively straightforward, save for a complication with the way the ingredients were stored in the object. There were 20 placeholder ingredient key-value pairs, and if the recipe required fewer than that then each numbered ingredient property after the final one was stored as an empty string (for example, strIngredient9, strIngredient10…in an eight-ingredient meal object). So we inserted a docile twentyfold for-loop to fill out the ingredients list while excluding from it any empty strings.

```
function loadRecipe(meal){
    recipeImage.src = meal.strMealThumb
    recipeInstructions.textContent = meal.strInstructions
    recipeName.textContent = meal.strMeal
    recipeIngredients.innerHTML = ""
    for (let i = 1; i < 21; i++){
        let ingredientName = meal[`strIngredient${i}`]
        let ingredientMeasure = meal[`strMeasure${i}`]
        let ingredientEntry = ingredientMeasure + ' ' + ingredientName
        const li = document.createElement("li")
        if (ingredientName != "" && ingredientName != null){
            li.textContent = ingredientEntry
            recipeIngredients.append(li)
        }   
    }
}
```

Then we wrote a loadBanner() function to iterate through ten “latest” meals (whatever that means, but again here the priority was practicing communicating with and accommodating an API) and represent their thumbnails in a top-of-page banner. Herein we called a click-obsessed event listener to make sure whenever one of these was selected by the cursor, its underlying recipe would load into the main display (name, directions, ingredients), with the help of a certain loadMeal() (functionally identical to loadRandom()). 

Searching by ingredients proved equal to clearing and reloading the banner (and we already had this function) except this time with the results of the API’s filter method. Once the submit form was in place and prepared to record items in the hungry user’s pantry, we needed only to reuse the functions we already wrote. Two complications arose. _Primo_, the API is reached by URL, so inputs are case-sensitive and desire underscores in lieu of spaces. Chicken Breast is no good there, even if that’s what the user types, since what we need is chicken_breast. So we patched that up with a handy textify() function that archaically iterated through the characters of the string and groomed them to the exacting standards of the URL. (I also used this opportunity to hardcode a conversion from ‘eggplant’ to ‘aubergine’ so that American users wouldn’t miss out on Baingan Bharta). _Secondo_, the filter results are pruned down meal object, without most of the metadata required, albeit with a meal ID. A getMealById() function utilizing the API’s lookup method solved this problem neatly. 

```
function textify(string){
    let newString = "";
    for (letter in string){
        if (string[letter] == " "){
            newString = newString + "_"
        } 
        else{
            newString = newString + string[letter].toLowerCase()
        }
    }
    if (newString == "eggplant"){
        newString = "aubergine"
    }
    return newString
}
```

Feeling rather omnipotent by this point, we decided to haughtily add another form kindly requesting an email address to which a shopping list would be sent. The technical process here was adding an event listener fastened to a submit form which would launch the email (window.open(mailto and interpolations)). We availed ourselves of an encodeURIComponent method which preened the ingredient list for the email format. 

```
function sendEmail() {
    emailForm.addEventListener("submit", (e) =>{
        let body = encodeURIComponent(recipeIngredients.innerText)
        e.preventDefault()
        const address = e.target["address"].value;
        const subject = encodeURIComponent("Here Is Your Recipe Shopping List!")
        window.open(`mailto:${address}?subject=${subject}&body=${body}`)
    })
}
```

Finally we had the CSS to wrangle with. Suffice it to say a lot of time was spent wrestling with buttery divs losing their shapes, slipping and sliding in every direction, if not going so far as to clamber on top of one another like box turtles.  We eventually agreed that flex-boxes would be the most convenient solution. But some things are better tackled after lunch. I wonder what I can make with a fridgeful of courgettes?