Nakwon Yoon
Nakwon Yoon

Reputation: 11

How can I create two conditions in if statment

enter image description here All the information is getting from DrinkAPI, and this API server did not make each array for the element sadly.. haha I am trying to get rid of that blank box if you can see the image (on the bottom link). In the Array from API it was always null instead of this situation. Is there any way to get rid of "" by using if statement? and if you guys can make more functions efficiently please advise me!

function cardBuilder(xinstructions, xdrinkName, ximgUrl, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15,
    i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) {

    var cardstring = ' <div style="width: 24rem;" class="card results-card"><img class="card-img" src="' + ximgUrl +
        '"alt="Drink"><div class="card-body"><h5 class="card-title">' + xdrinkName + '</h5><p class="card-text">' + xinstructions + '</p>';

    var ingreds = '<ul class="list-group list-group-flush ingredients-list">';
    var fact = "";
    if (i1 != null && m1 != null ) {
        fact += "<li class='list-group-item'>" + m1 + " " + i1 + "</li>"
    } else if (i1 != null) {
        fact += "<li class='list-group-item'>" + " " + i1 + "</li>"
    }
    if (i2 != null && m2 != null) {
        fact += "<li class='list-group-item'>" + m2 + " " + i2 + "</li>"
    } else if (i2 != null) {
        fact += "<li class='list-group-item'>" + " " + i2 + "</li>"
    }
    if (i3 != null && m3 != null) {
        fact += "<li class='list-group-item'>" + m3 + " " + i3 + "</li>"
    } else if (i3 != null) {
        fact += "<li class='list-group-item'>" + " " + i3 + "</li>"
        }
    if (i4 != null && m4 != null) {
        fact += "<li class='list-group-item'>" + m4 + " " + i4 + "</li>"
    } else if (i4 != null) {
        fact += "<li class='list-group-item'>" + " " + i4 + "</li>"
    }
    if (i5 != null && m5 != null ) {
        fact += "<li class='list-group-item'>" + m5 + " " + i5 + "</li>"
    } else if (i5 != null) {
        fact += "<li class='list-group-item'>" + " " + i5 + "</li>"
    }
    if (i6 != null && m6 != null) {
        fact += "<li class='list-group-item'>" + m6 + " " + i6 + "</li>"
    } else if (i6 != null) {
        fact += "<li class='list-group-item'>" + " " + i6 + "</li>"
    }
    if (i7 != null && m7 != null) {
        fact += "<li class='list-group-item'>" + m7 + " " + i7 + "</li>"
    } else if (i7 != null) {
        fact += "<li class='list-group-item'>" + " " + i7 + "</li>"
    }
    if (i8 != null && m8 != null) {
        fact += "<li class='list-group-item'>" + m8 + " " + i8 + "</li>"
    } else if (i8 != null) {
        fact += "<li class='list-group-item'>" + " " + i8 + "</li>"
    }
    if (i9 != null && m9 != null) {
        fact += "<li class='list-group-item'>" + m9 + " " + i9 + "</li>"
    } else if (i9 != null) {
        fact += "<li class='list-group-item'>" + " " + i9 + "</li>"
    }
    if (i10 != null && m10 != null) {
        fact += "<li class='list-group-item'>" + m10 + " " + i10 + "</li>"
    } else if (i10 != null) {
        fact += "<li class='list-group-item'>" + " " + i10 + "</li>"
    }
    if (i11 != null && m11 != null) {
        fact += "<li class='list-group-item'>" + m11 + " " + i11 + "</li>"
    } else if (i11 != null) {
        fact += "<li class='list-group-item'>" + " " + i11 + "</li>"
    }
    if (i12 != null && m12 != null) {
        fact += "<li class='list-group-item'>" + m12 + " " + i12 + "</li>"
    } else if (i12 != null) {
        fact += "<li class='list-group-item'>" + " " + i12 + "</li>"
    }
    if (i13 != null && m13 != null) {
        fact += "<li class='list-group-item'>" + m13 + " " + i13 + "</li>"
    } else if (i13 != null) {
        fact += "<li class='list-group-item'>" + " " + i13 + "</li>"
    }
    if (i14 != null && m14 != null) {
        fact += "<li class='list-group-item'>" + m14 + " " + i14 + "</li>"
    } else if (i14 != null) {
        fact += "<li class='list-group-item'>" + " " + i14 + "</li>"
    }
    if (i15 != null && m15 != null) {
        fact += "<li class='list-group-item'>" + m15 + " " + i15 + "</li>"
    } else if (i15 != null) {
        fact += "<li class='list-group-item'>" + " " + i15 + "</li>"
    }
    fact += "</ul>";
    cardstring += fact + "</div>";
    return cardstring;

}

Upvotes: 0

Views: 156

Answers (4)

3limin4t0r
3limin4t0r

Reputation: 21120

This is not a stand-alone answer, but rather supplements the answer of blex. To get a structure similar to the one used in the linked answer you'll have to convert the API data. This can be done in multiple ways.

Here is an example of how this can be done:

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
const escapeRegExp = string => string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');

function extractArrayProperties(obj, ...names) {
  if (names.length == 0) return [];

  const nameValues   = new Map(names.map(name => [name, []]));
  const namesPattern = names.map(escapeRegExp).join("|");
  const regex        = new RegExp(`^(${namesPattern})(\\d+)$`);

  for (const [prop, value] of Object.entries(obj)) {
    const [match, name, nr] = prop.match(regex) || [];
    if (!match) continue;
    const index = parseInt(nr, 10) - 1;
    nameValues.get(name)[index] = value;
  }

  const lengths = names.map(name => nameValues.get(name).length);
  const maxLength = Math.max(...lengths);
  return Array.from({ length: maxLength }).map((_, index) => {
    const entries = names.map(name => [name, nameValues.get(name)[index]]);
    return Object.fromEntries(entries);
  });
}

const drink = {
  // ...
  "strIBA": null,
  "strIngredient1": "Vodka",
  "strIngredient2": "Sugar Syrup",
  "strIngredient3": "Passion fruit juice",
  "strIngredient4": "",
  "strIngredient5": "",
  "strIngredient6": "",
  "strIngredient7": "",
  "strIngredient8": null,
  "strIngredient9": null,
  // ...
  "strInstructions": "Pour all ingredients into a glass and ...",
  "strInstructionsDE": null,
  "strInstructionsES": null,
  "strInstructionsFR": null,
  "strInstructionsZH-HANS": null,
  "strInstructionsZH-HANT": null,
  "strMeasure1": "1 shot",
  "strMeasure2": "1/2 shot",
  "strMeasure3": "Full Glass",
  "strMeasure4": "",
  "strMeasure5": "",
  "strMeasure6": "",
  "strMeasure7": "",
  "strMeasure8": null,
  "strMeasure9": null,
  // ...
};

console.log("ingredients with empty values:");
let ingredients = extractArrayProperties(drink, "strIngredient", "strMeasure");
console.log(ingredients);

console.log("ingredients without empty values:");
// Use `filter` to remove all objects with falsy strIngredient
// value. Both null and "" are considered falsy.
ingredients = ingredients.filter(ingredient => ingredient.strIngredient);
console.log(ingredients);

This solution loops over all (iterable) properties of an object trying to find something that matches the regex (name followed by a number). The number is converted into an integer (using base 10) and mapped to its index by subtracting 1 (your properties start with 1 not 0). The value is stored in an array saved in an lookup map under the index calculated above.

We check the longest array size when all properties are looped and create an empty array with that size. For each slot in this array we loop over all names and get the value of its index position.

const data = { keyB2: "e", keyA2: "b", keyA1: "a", keyB1: "d" keyA3: "c" };
extractArrayProperties(data, "keyA", "keyB");

// Will have lookup map (I'll use an object to represent a Map):
// Values are stored based on their number keyA1 has nr 1 and is
// stored at index 0, keyB2 has nr 2 and is stored at index 1.
const nameValues = {
  keyA: ["a", "b", "c"],
  keyB: ["d", "e"     ],
};

// The max length is 3. We create an array with this length and
// set the values based on the index.
[
  { keyA: "a", keyB: "d"       },
  { keyA: "b", keyB: "e"       },
  { keyA: "c", keyB: undefined },
]

Demo

If we combine this with Blex's answer, we get a fully working demo, using the real API:

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
const escapeRegExp = string => string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');

// Our utility function, to extract the ingredients
function extractArrayProperties(obj, ...names) {
  if (names.length == 0) return [];

  const nameValues = new Map(names.map(name => [name, []]));
  const namesPattern = names.map(escapeRegExp).join("|");
  const regex = new RegExp(`^(${namesPattern})(\\d+)$`);

  for (const [prop, value] of Object.entries(obj)) {
    const [match, name, nr] = prop.match(regex) || [];
    if (!match) continue;
    const index = parseInt(nr, 10) - 1;
    nameValues.get(name)[index] = value;
  }

  const lengths = names.map(name => nameValues.get(name).length);
  const maxLength = Math.max(...lengths);
  return Array.from({
    length: maxLength
  }).map((_, index) => {
    const entries = names.map(name => [name, nameValues.get(name)[index]]);
    return Object.fromEntries(entries);
  });
}

// Card builder
function cardBuilder({ strInstructions, strDrink, strDrinkThumb, ingredients }) {
  return `
    <div style="width: 24rem;" class="card results-card">
      <img class="card-img" src="${strDrinkThumb}"alt="Drink">
      <div class="card-body">
        <h5 class="card-title">${strDrink}</h5>
        <p class="card-text">${strInstructions}</p>
        <ul class="list-group list-group-flush ingredients-list">
        ${
        ingredients.map(({strIngredient, strMeasure}) => 
          `<li class='list-group-item'>${strMeasure || ''} ${strIngredient || ''}</li>`
        ).join('')
        }
        </ul>
      </div>
    </div>`;
}

// Get the data from the API
fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=Passion%20Fruit%20Martini')
  .then(res => res.json())
  .then(({ drinks: [drink] }) => {
    // Extract ingredients
    const ingredients = extractArrayProperties(drink, "strIngredient", "strMeasure")
                        .filter(ingredient => ingredient.strIngredient);
    // Create a recipe
    const recipe = {
      ...drink,
      ingredients
    };
    // Display it
    document.getElementById("drink-container").innerHTML = cardBuilder(recipe);
  })
  .catch(console.error);
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<div id="drink-container"></div>

Upvotes: 1

user120242
user120242

Reputation: 15268

Using the drinks data API (got URL from blex's comment and 3limin4t0r's answer).
Assumes ingredient properties are always in the form str{Measure/Ingredient}{1..15}.
Loops over array in drinks: property if you have multiple drinks.
Uses flatMap to filter null ingredients and map to li element strings in one step.

function cardBuilder(drinkData) {
  const { strInstructions, strDrink, strDrinkThumb } = drinkData
  return `
    <div style="width: 24rem;" class="card results-card">
      <img class="card-img" src="${strDrinkThumb}" alt="Drink">
      <div class="card-body">
        <h5 class="card-title">${strDrink}</h5>
        <p class="card-text">${strInstructions}</p>
        <ul class="list-group list-group-flush ingredients-list">
        ${
          // it's always 15 ingredients maximum, extract properties str{name}{1..15}
          Array(15).fill().flatMap((x,i)=> {
            const m = drinkData[`strMeasure${i+1}`],
                  ing = drinkData[`strIngredient${i+1}`]
            return ing ?
              `<li class='list-group-item'>${m || ''} ${ing || ''}</li>` : []
              // if ingredient null filter out, else return li element string
          }).join('')
        }
        </ul>
      </div>
    </div>`;
}

// Get the data from the API
fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=Passion%20Fruit%20Martini')
  .then(res => res.json())
  .then(data => {
    // in case you query more than one drink
    for(const drink of data.drinks)
      document.body.innerHTML += cardBuilder(drink)
  })

Using spread and rest syntax, based on the code you posted:

function cardBuilder(xinstructions, xdrinkName, ximgUrl, ...mi) {
    return `<div style="width: 24rem;" class="card results-card">
  <img class="card-img" src="${ximgUrl}" alt="Drink">
  <div class="card-body">
    <h5 class="card-title">${xdrinkName}</h5>
    <p class="card-text">${xinstructions}</p>
    <ul class="list-group list-group-flush ingredients-list">
    ${
      // divide mis array in half.  filter out where both m and i are null
      // map the rest to li element strings
      mi.splice(0,mi.length/2).flatMap((m,i)=>
        mi[i] ?
         `<li class='list-group-item'>${m || ''} ${mi[i] || ''}</li>` : [])
      .join('')
    }
    </ul></div></div>`;
}

document.body.innerHTML=
  cardBuilder('instruct', 'drinkname', 'someimage.png',
  // create array, spread to params to fill in m1..m4 and i1..i5 for testing
  ...Array(30).fill(null).map((x,i)=>i%15 < 5 || i===20 ? `${i}` : null))

Upvotes: 1

blex
blex

Reputation: 25634

Look at 3limin4t0r's answer! It combines both of our answers, and there is a fully working example at the end, using the actual API.

You can greatly simplify your code. Always think "DRY" (Don't Repeat Yourself).

Every time you are tempted to copy/paste a variable, function, or anything else by adding a number to its name, you can be sure it's a bad idea.

Here is how I would do it:

function cardBuilder({ instructions, drinkName, imgUrl, ingredients }) {
  return `
    <div style="width: 24rem;" class="card results-card">
      <img class="card-img" src="${imgUrl}"alt="Drink">
      <div class="card-body">
        <h5 class="card-title">${drinkName}</h5>
        <p class="card-text">${instructions}</p>
        <ul class="list-group list-group-flush ingredients-list">
        ${
        ingredients.map(x => 
          x.name
          ? `<li class='list-group-item'>${x.measurement || ''} ${x.name || ''}</li>`
          : ''
        ).join('')
        }
        </ul>
      </div>
    </div>`;
}

const recipe = {
  drinkName: 'Passion fruit Martini',
  imgUrl: 'https://cdn.shopify.com/s/files/1/0281/1189/6681/files/pornstar-martini-1.jpg?v=1582960820',
  instructions: 'Pour all ingredients into a glass and stir',
  ingredients: [
    { name: 'Vodka', measurement: '1 shot' },
    { name: 'Sugar syrup', measurement: '1/2 shot' },
    { name: 'Passion fruit juice', measurement: 'Full Glass' }
  ]
};

document.body.innerHTML = cardBuilder(recipe);
.card-img {
  display: block;
  width: 10rem;
}

Upvotes: 2

Mustafa Ali
Mustafa Ali

Reputation: 65

So your code is not really good here is mine

/**
 * Dummy data 😆
 *
 *
 * I notice that your data is an object and every key should have pair
 * and there is no such a case when there is a key with out or with null pair
 * as well as the "Ingredient" came first and then "Measure"
 * if there is any feel free to comment down
 */

const data = {
  strIngredient1: 'Vodka',
  strIngredient2: 'Sugar Syrup',
  strIngredient3: 'Passion fruit juice',
  strIngredient4: null,
  strIngredient5: '',
  strMeasure1: '1 shot',
  strMeasure2: '1/2 shot',
  strMeasure3: 'Full Glass',
  strMeasure4: '',
  strMeasure5: null,
};

/**
 *
 * @param {*} data Object
 * @return object with two arrs { ingredient, measure }
 *
 */
const adapter = (data = {}) => {
  const cleanArray = Object.values(data).filter(
    (item) => item && item.length !== 0
  );
  const length = cleanArray.length;
  const ingredient = cleanArray.slice(0, length / 2);
  const measure = cleanArray.slice(length / 2, length);
  return { ingredient, measure };
};

console.log({ result: adapter(data) });

** There are some edge cases that I did not take it or see it so feel free to comment so i can maybe change the code **

Upvotes: 0

Related Questions