Home > Blockchain >  Vue.js is there an elegant way to loop for map keys in axios?
Vue.js is there an elegant way to loop for map keys in axios?

Time:10-03

I am proceeding with Vue.js exercises that I create. I am populating a json api to a table, everything works but I am facing a limitation where there is multiple keys in api with almost same name(strIngredient1,strIngredient2,strIngredient3, ..etc) and some of these keys are null. Is there a way to include regex when doing mapping searching for the substring(strIngredientx) where x is a number ? and also to exclude the null values? I did use axios but not sure if is the prefect way, this is my code:

Ingredient.vue( parent):

<template>
  <div>
    <table class="table table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">Name</th>
          <th scope="col">Category</th>
          <th scope="col">strIBA</th>
          <th scope="col">Ingredients</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in all_cocktails" v-bind:key="item">
          <td>{{ item.id }}</td>
          <td>{{ item.name }}</td>
          <td>{{ item.strIBA }}</td>
          <td>{{ item.category }}</td>
          <td><subComponent :item="item"></subComponent></td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
import subComponent from "./subComponent";

import axios from "axios";
export default {
  data() {
    return {
      loading: false,
      all_cocktails: {},
    };
  },
  components: {
    subComponent,
  },
  async mounted() {
    this.loading = true;
    await this.getData();
  },
  computed: {},
  methods: {
    getData() {
      axios
        .get(
          "https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita"
        )
        .then((response) => (this.all_cocktails = response.data.drinks))
        .then(
          (response) =>
            (this.all_cocktails = this.all_cocktails.map((d) => ({ //using map to pick the keys that I want.
              id: d.idDrink,
              name: d.strDrink,
              category: d.strCategory,
              strIBA: d.strIBA,
              Ingredients: [ //here is there a way to loop for substring and not null instead of going through all of them ?
                d.strIngredient1,
                d.strIngredient2,
                d.strIngredient3,
              ],
            })))
        )
        .catch((error) => console.log(error))
        .finally(() => (this.loading = false));
    },
  },
};
</script>

<style>
</style>

subComponent.vue (child):

<template>
  <div>
    <select>
      <option
        v-for="(item, index) in item.Ingredients"
        :key="index"
        v-bind:value="item"
      >
        {{ item }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  props: {
    item: {},
  },
  data() {
    return {};
  },
};
</script>

CodePudding user response:

is this clean enough?

axios
    .get("https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita")
    .then((response) => (this.all_cocktails = response.data.drinks))
    .then((response) =>
        (this.all_cocktails = this.all_cocktails.map((d) => {
            let obj = { 
                id: d.idDrink,
                name: d.strDrink,
                category: d.strCategory,
                strIBA: d.strIBA,
            }
            let Ingredients = []
            for(let i = 0; i < Object.keys(d).length; i  ) {
                if(d["strIngredient" i]) Ingredients.push(d["strIngredient" i])
            }
            obj.Ingredients = [...new Set(Ingredients)]
            return obj
        })))

output:

{
  id: '178332',
  name: 'Smashed Watermelon Margarita',
  category: 'Cocktail',
  strIBA: null,
  Ingredients: [
    'Watermelon',
    'Mint',
    'Grapefruit Juice',
    'Lime',
    'Tequila'
  ]
}

CodePudding user response:

When you transform this.allCoktails after getting the request, you may create an array for the Ingredients property that contains not null ingredients like this :

// current element (we are inside the 'map')
const d = {
    "strMeasure1": "1/2 cup",
    "strIngredient1": "Watermelon",
    "strIngredient2": "Mint",
    "strIngredient3": null,
    "strIngredient4": null,
}

// getting the keys
const keys = Object.keys(d)

// filtering the keys (keeping not null and ingredient related keys)
const nonNullIngredientsRelatedKeys = keys.filter(key => key.includes('strIngredient') && d[key] !== null)

// mapping of keys and values
const ingredients = nonNullIngredientsRelatedKeys.map(key => d[key])

console.log(ingredients)

Here is a one-liner version :

Object.keys(d).filter(key => key.includes('strIngredient') && d[key] !== null).map(key => d[key])

CodePudding user response:

let data = [ { a: 1, b: 2, strIngredient1: 3, strIngredient2: 4, strIngredient3: null }, { a: 1, b: 2, strIngredient1: 3, strIngredient2: 4, strIngredient3: null }, { a: 1, b: 2, strIngredient1: 3, strIngredient2: 4, strIngredient3: null }]

console.log(

  data.map(itm => Object.entries(itm)
   .filter(([key, value]) => (key.indexOf('strIngredient') !== -1 && value) || key.indexOf('strIngredient') === -1)
   .reduce((obj, itm) => ({ ...obj, [itm[0]]: itm[1]}), {}))

)

For your code, it will be used like:

(this.all_cocktails = this.all_cocktails.map((d) => ({ //using map to pick the keys that I want.
  id: d.idDrink,
  name: d.strDrink,
  category: d.strCategory,
  strIBA: d.strIBA,
  Ingredients: Object.entries(d)
    .filter(([key, value]) => (key.indexOf('strIngredient') !== -1 && value))
    .reduce((obj, itm) => ({ ...obj,
      [itm[0]]: itm[1]
    }), {}),
})))
  • Related