Search code examples
arraysvue.jsvuejs2limitnested-loops

How to return only top 5 records in Vue js nested loop


I need to iterate over shoppingItem (items) inside shoppingOrder (orders). There are three orders. The first order has one item (itemid:1), second order has six items (itemid:2,3,4,5,6,7), third order has one item (itemid:8). I need to show only the top five items. i.e., 1,2,3,4,5 but the current code only limits the item in the second order, showing five items inside. The final output comes like 1,2,3,4,5,6,8

If first order has five items the loop should exit, if first order has one item and second order has six items, it has to show 1 in order 1 and 2,3,4,5 in order2 and exit before order3. But in my example, using order.shoppingItem.slice(0,5) only limits the items in the second order. It is not limiting the total items. How do I resolve this issue? I am using Vue JS version 2

NestedLoop.vue

<template>
  <div>
    <div v-for="order in shoppingOrder" :key="order.orderId">
      <div v-for="item in order.shoppingItem.slice(0,5)" :key="item.itemId">
        {{item.itemId}}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "NestedLoop",
  data() {
    return {
      shoppingOrder: [
        {
          orderId: 1,
          orderDate: "7/30/2020",
          orderStatus: "Dispatched",
          shoppingItem: [
            {
              itemId: 1,
              itemName: "Pen",
              itemQuantity: "1",
              itemPrice: "10.00"
            }
          ]
        },
        {
          orderId: 2,
          orderDate: "7/25/2020",
          orderStatus: "Ordered",
          shoppingItem: [
            {
              itemId: 2,
              itemName: "Notebook",
              itemQuantity: "2",
              itemPrice: "40.00"
            },
            {
              itemId: 3,
              itemName: "Scale",
              itemQuantity: "3",
              itemPrice: "100.00"
            },
            {
              itemId: 4,
              itemName: "Sharpener",
              itemQuantity: "1",
              itemPrice: "10.00"
            },
            {
              itemId: 5,
              itemName: "DocumentFolder",
              itemQuantity: "1",
              itemPrice: "10.00"
            },
            {
              itemId: 6,
              itemName: "PencilBox",
              itemQuantity: "5",
              itemPrice: "140.00"
            },
            {
              itemId: 7,
              itemName: "SketchBox",
              itemQuantity: "5",
              itemPrice: "10.00"
            }
          ]
        },
        {
          orderId: 3,
          orderDate: "7/34/2020",
          orderStatus: "Dispatched",
          shoppingItem: [
            {
              itemId: 8,
              itemName: "Sketch",
              itemQuantity: "1",
              itemPrice: "10.00"
            }
          ]
        }
      ]
    };
  },
  methods: {}
};
</script>

<style scoped>
</style>

Result

1
2
3
4
5
6
8

Expected only to return top 5 items like this (1 in order1 and then 2,3,4,5 in order2),

1
2
3
4
5

Solution

  • I love how succinct @Gaetan C's answer is, but .flat is a relatively new method that will require poly-filling for browsers if you are using Vue-cli 3. See this Github issue for more details. If you run into any challenges, you may need to manually edit the poly-fill option of the babel preset.

    For more compatibility among other browsers or if you are using vue cli 2 or below, I present this solution.

    computed: {
      firstFiveShoppingItems: {
         let initialShippingItem = [];
         for (const order of this.shoppingOrder) {
       
           if (initialShippingItem.length + order.shoppingItem.length >=5) {
             return [...initialShippingItem, ...order.shoppingItem].slice(0, 5);
           }
    
           initialShippingItem = [...initialShippingItem, ...order.shoppingItem]
         }
         return initialShippingItem;
      }
    }

    Then in your template, you add

    <div v-for="item in firstFiveShoppingItems" :key="item.itemId">
      {{item.itemId}}
    </div>

    As I said, it's not as elegant or succinct as @Gaetan C's answer but it will be more compatible among other browsers and you won't need to go through headaches with poly-fill configurations.

    Another thing I like about my solution is that it doesn't iterate over all shopping item arrays like @Gaetan C's answer. It breaks when the result is obtained.