Increasing the value of a food topping element within a v-for list of toppings when clicking on the "+ add" button in Vue

I'm a newcomer to the world of JavaScript and Vue.js, currently working on a project to automate the ordering process for my pizza delivery pizzeria.

On the website, I have a list of toppings that customers can choose from. They have the option to select up to 4 toppings from the list, and they can choose the same topping 2, 3, or 4 times.

To manage this, I implemented a counter for each item in the list. The counter keeps track of the selected topping names in an array with a limit of 4, and this approach has been successful.

My question is, how can I allow users to select a topping and increase the quantity on the interface?

Below you can find my code snippet and some visual references:

Link to the CodePen

Vue.component('topping-selector', {
  data() {
    return {
      selectedToppings: [],
      toppingLimit: 4
    };
  },
  methods: {
    addTopping(topping) {
      if (this.selectedToppings.length < this.toppingLimit) {
        this.selectedToppings.push(topping);
      } else {
        console.log('You have reached the maximum number of toppings allowed.');
      }
    },
    increaseToppingAmount(topping) {
      const index = this.selectedToppings.indexOf(topping);
      if (index !== -1) {
        this.selectedToppings.splice(index, 1);
        this.selectedToppings.push(topping);
      }
    }
  }
});

Below is the HTML and template structure:

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,minimum-scale=1">
    <title>Zune Pizza</title>
    <link rel="stylesheet" href="zunepizza.css">
    <link async href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link async href="https://fonts.googleapis.com/css?family=Roboto&display=swap" rel="stylesheet">

    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
</head>

<body>
    <div id="app">
        <topping-selector></topping-selector>
    </div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</body>

</html>

Zune Pizza Topping Counter Display

Desired interface similar to the image:

iFood Topping Selection Interface

Answer №1

If you're looking to achieve a similar effect, check out this example: https://codepen.io/jasik/pen/NWxdLRg

<div id="menu">
    <ul v-for="item in menuItems">
      <li>
        <div class="item-details">
          <h3 class="item-name">{{item.name}}</h3>
          <div class="tag">
            <h5>{{item.type}}</h5>
          </div>
          <p class="item-description">{{item.desc}}</p>
        </div>
        <div class="item-image">
          <div class="flavorCounter" :id="item.name">
            <button @click="item.counter++" :disabled="item.counter === 4" :flavor="item.name" class="addFlavor controller-button"> + </button>

            <input :id='item.name' type="number" v-model="item.counter" class="flavorQuantity">

            <button @click='item.counter--' :disabled="item.counter === 0" :flavor='item.name' class="addFlavor controller-button"> - </button>
          </div>
          <img src="img/menu/item.jpg" alt="">
        </div>
      </li>
    </ul>
  </div>

data: {
    menuItems: []
  },
  created() {
    axios
      .get(
        "https://example-api.com/menu/items"
      )
      .then((response) => {
        let edited = response.data.items;
        edited.forEach((e) => {
          e.counter = 0;
        });
        this.menuItems = edited;
      })
      .catch((error) => {})
      .finally(() => {});
  },
  methods: {}

I hope this example proves to be useful. Good luck with your project!

Answer №2

If you want to implement this functionality, consider adding a new property, such as quantity, to your items:

this.menu = response.data.menu.map(item => ({ ...item, quantity: 0 }))

Next, you can link the quantity to the elements in your HTML code and adjust it as needed:


<!--Remember to add a unique :key attribute for optimal Vue performance-->
<ul v-for="(meal, i) in menu" :key="i">
  ...
  <button @click="meal.quantity < 4 ? meal.quantity++ : ''" ... > + </button> 
  <input v-model="meal.quantity"...>
  <button @click="meal.quantity > 0 ? meal.quantity-- : ''" ... > - </button>
  ...
</ul>

If you need to identify the selected items, simply filter out items with a quantity greater than 0:

this.selectedItems = this.menu.filter(({ quantity }) => quantity > 0);

I hope this explanation helps clarify the process for you.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Reveal the MongoDB database connection to different sections within a Next.js 6 application

Currently developing an application using Next.js v6, and aiming to populate pages with information from a local mongodb database. My goal is to achieve something similar to the example provided in the tutorial, but with a twist - instead of utilizing an ...

The fancybox's excess content is concealed

I've recently integrated fancybox 2 into my project and have encountered an issue when appending HTML content to the modal. I disabled scrolling, but now any overflowing content is being hidden. Could this be related to the max-height of the modal? Ho ...

What is the best method for incorporating dynamic page transitions when navigating between individual pages?

Let's say I have the following pages: red.html blue.html green.html My goal is to create links from red.html to blue.html and red.html to green.html. When attempting to use page anchors and iframes, I encountered an issue where scrolling from red.h ...

What is the best way to divide the Jquery.js file into smaller, separate files?

My web server has a strict file size limit of 64KB and I heavily rely on jQuery for my project. Unfortunately, using any other library like zepto is not an option. The minified size of jQuery alone is 95KB, so I need to split it into two smaller files. C ...

How can I dynamically update the content of the right side of the side navbar by clicking on navbar links?

I have a side-navigation bar with content on the right side. How can I display specific content on the right side when clicking on a navigation link? For example, only show the name when clicking on the name link and only show the password field when click ...

What is the best way to utilize the oninput function in Jade?

input(type='range', id= 'inputSlider', min='0', max='255', value='50', step='1', oninput=showValue(this.value)) span#outputText 50 script. var socket = io.connect(); socket.on(& ...

The image has been restricted from view due to CORS specifically on Windows operating systems

This Vue component includes a photo block and an "edit" button. <template> <div> <tui-image-editor ref="editor" > </tui-image-editor> <div class=""> <img :src="img&qu ...

Translate a portion of a painting by utilizing context.putImageData()

I am attempting to gradually fill a canvas with pieces of the original image. To achieve this, I need each square of the image to be filled in iteratively on the canvas. To optimize performance, my approach involves rendering the original image onto an of ...

Can someone guide me on the process of adding a personalized emoji to my discord bot?

After creating my own discord bot, I'm ready to take the next step and add custom emojis. While tutorials have helped me understand how to use client.cache to type an emoji, I'm unsure of how to upload them and obtain their ID for use in my bot. ...

What is causing the dysfunction of angular2 form when used with the HTML <form> tag?

Can someone explain the strange behavior of the <form> element in ng2 to me? I have noticed something odd and need some clarification :) To demonstrate, I have created a simple Plunker example at this link: https://plnkr.co/edit/vdrHJBNdd26y6YhPXTHD ...

Receiving a notification when attempting to log in with incorrect credentials

I am currently working on an Angular login page implementation using a username and password setup. When the user enters incorrect credentials, I want to display an alert message indicating the same. Here is the HTML code snippet for the form: <form [f ...

I am seeking to retrieve data from MongoDB by utilizing the limit feature, while also sending a specific query

I'm currently facing some confusion with the limit functionality in MongoDB. I want my code to specifically retrieve data for just two hotels by sending a query request from the backend. export const getHotels = async (req, res, next) => { try ...

React error: File undefined (cannot be exported)

Encountering an issue while attempting to follow a tutorial: src/components/MyApp.js Line 17:18: 'myApp' is not defined no-undef Search for the keywords to learn more about each error. This is what my myApp.js file contains: import React fr ...

Can you show me how to access the elements of a JSON object named "foo.txt" and print them out?

Currently, I am working with JavaScript and JSON. My goal is to retrieve data from an API where objects contain specific details. Specifically, I need to display the details of an object named "foo.txt" which includes elements such as size, raw_url, conten ...

Why does Vue reset a v-binded property when a v-model property changes?

Apologies if the title doesn't fully capture my query. In the brief Vue code snippet below, I have 2 input fields. One utilizes v-bind and the other uses v-model. I am puzzled as to why changing the second input resets the value of the first input. ...

Displaying a dynamic map with real-time coordinates sourced from a database using a combination of ajax and php

I'm currently facing an issue where my solution to retrieve coordinates for a specific place from a database and display a map centered on them is not working as expected. The problem seems to be arising because the map is being initialized without an ...

The SetInterval function will continue to run within a web component even after the corresponding element has been removed from the

I am currently engaged in developing a straightforward application that coordinates multiple web components. Among these components, there is one that contains a setInterval function. Interestingly, the function continues to run even after the component it ...

Creating a custom navigation bar that elegantly fades away with a smooth animation as you scroll down the page is a must-have

How can I create a navigation bar that disappears when scrolling, with a smooth animation? This is the progress I have made so far. HTML: <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="css/style.css" type="tex ...

Implementing pagination and filtering in a single MERN controller

Is it possible to implement pagination and filtering in the same controller? Filter service:- const filterPosts = async (filterData, token) => { const config = { headers: { Authorization: `Bearer ${token}`, }, data: { ...

The 'fetch' operation could not be completed on the current window due to a TypeError

The error message I am receiving is: TypeError: Failed to execute 'fetch' on 'Window' : The provided value is not of type '(sequence<sequence> or record<ByteString, ByteString>)'. My current challenge involves fetc ...