What is the method for modifying the array that has been generated using Vue's "prop" feature?

According to the Vue documentation, a prop is passed in as a raw value that may need transformation. The recommended approach is to define a computed property using the prop's value.

If the "prop" is an array of objects, how can it be transformed into a computed array and then mutated? I followed the documentation but am unsure about mutating it.

In the example below, the component accepts an array of items

Array<{ ID: string, lettering: string; }>
. It renders buttons for each item.

  1. Clicking a button should change its color.
  2. Clicking the same button again should revert it to its initial state.

https://i.sstatic.net/nwnon.png

Experience it here

<template>
  <div>
    <button  
      v-for="(item, index) in selectableItems"
      :key="`BUTTON-${item.ID}`"
      :class="{ selected: item.selected }"
       @click="() => {onButtonClicked(item, index) }"
    > {{ item.lettering }}
    </button>
  </div>  
</template>

I generate the selectableItems from the items array. Each item in selectableItems has an additional property selected along with the original properties of the item.

export default {
  name: "HelloWorld",
  props: {
    items: Array
  },
  computed: {
    selectableItems: function () {
      const selectableItems = [];
      this.items.forEach((item) => {
        selectableItems.push({
          ID: item.ID,
          lettering: item.lettering,
          selected: false
        });
      });
      return selectableItems;
    }
  },
  methods: {
    onButtonClicked: function(item, index) {
      if (item.selected) {
        this.selectableItems[index].selected = false;
      } else {
        this.selectableItems[index].selected = true;
      }
      console.log(this.selectableItems);
    }
  }
};

The buttons in Vue do not re-render currently.

I understand that mutating the getter is not the right way to go. But what is the correct approach to mutate the array?

Forbidden solution

Passing the

{ ID: string, lettering: string; selected: boolean; }
via props instead of
{ ID: string, lettering: string; }
is against the rules.
{ ID: string, lettering: string; }
represents the pure model and should not contain any information about UI. selected: boolean; is strictly for UI purposes only.

Answer №1

If you're in a hurry, check out this quick example on jsfiddle https://jsfiddle.net/hgvajn5t/

To save time, I've skipped creating two components and accessed the data directly as props.

The key is to define your selected buttons in your data

data () {
    return {
      selectedItems: []
    }
},

The next step is to keep track of which items are selected and which are not

onButtonClicked: function(item){
  let index = this.selectedItems.indexOf(item.ID)
  if (index > -1) {
    this.selectedItems.splice(index, 1)
  } else {
    this.selectedItems.push(item.ID)
  }
}

The onButtonClicked function takes the item as input and toggles its selection status

Lastly, update your binding to apply the selected class based on whether the item is in the selectedItems array or not

:class="{ selected: selectedItems.indexOf(item.ID) > -1 }"

Remember, this approach works best when each item's ID is unique.

In conclusion: This method may seem complicated at first, especially for beginners in Vue. It all boils down to how you structure your UI. Remember, avoid directly manipulating props. Using computed properties to enhance them is okay, but modifying computed properties is not recommended. If you need the select state outside the current component, consider emitting events to update the data source directly from the parent component. This way, you maintain a single source of truth instead of storing extra information about the items elsewhere.

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

Vue3 TypeScript may potentially have an object that is 'undefined'

This piece of code is Vue3 with TypeScript-based. export interface TenantDto { uuid: string; name: string; } export const useTenantStore = defineStore('tenant', { state: () => ({ tenants: [], }), actions: { setMyTenants: (pa ...

A guide on exporting the data type of a computed property in Vue3

I'm facing a challenge with my Vue3 component that interacts with GraphQL requests. After receiving a large JSON response, I utilize a computed property to extract the necessary value. Now, I aim to pass this extracted value as a prop to a child compo ...

jQuery's Multi-Category Filter feature allows users to filter content

I have been working on creating a filter function for my product list. The idea is that when one or more attributes are selected, it should fade out the elements that do not match. And then, if a filter is removed, those faded-out items should fade back in ...

Creating dynamic links within HTML through real-time updating

In my application, I have a feature that generates a list of words and converts them into clickable links. When the user clicks on a link, I want to extract the {{word.name}} from the HTML link without navigating to a new page. I simply need to retrieve th ...

Keep the multiselect dropdown list of the select component open

I am currently utilizing the Select component from material-ui-next. Overall, it functions quite smoothly. One scenario where I implement it is within a cell element of an Ag-Grid. Specifically, in this use case, I am making use of the multiselect feature ...

Is there a need to remove whitespace for additional characters?

Is there a function available that can trim specified characters or strings? For example: var x = '@@@hello world@@'; console.log(x.trim('@')); // outputs 'hello world' var y = 'hellohellohelloworld'; console.log(y ...

The onchange functionality is not functioning as expected

I've added an onchange event to the select box, but it doesn't seem to be working. Any suggestions would be greatly appreciated. Thank you in advance. HTML [<select id="notifyBy" ng-change="selectchange()" style="border:none" class="formtex ...

Changing colors in the rows of a table

Here is a fiddle I created to demonstrate my issue. https://jsfiddle.net/7w3c384f/8/ In the fiddle, you can see that my numbered list has alternating colors achieved through the following jQuery code: $(document).ready(function(){ $("tr:even").css("ba ...

Tips for personalizing the error message displayed on Webpack's overlay

Is there a way to personalize the error overlay output message in order to hide any references to loaders, as shown in this image: Any suggestions on how to remove the line similar to the one above from the overlay output? ...

Enhance the numerical value displayed in jQuery UI tooltips

I have folders with tooltips displaying text like '0 entries' or '5 entries' and so on. I am looking for a way to dynamically update this tooltip number every time an item is added to the folder. The initial count may not always start a ...

What is the best way to remove a MySQL entry with the help of Ajax and Jquery?

Seeking advice on integrating the post title into a jQuery .ajax call. Successfully able to create and display blog posts, now exploring options for adding delete and edit functionality. Currently focusing on delete as it seems more straightforward. Any su ...

What is the integration process of using Font Awesome with React?

After installing react-create-app using npm, I also added react-fontawesome. Now, I'm wondering how to include the css styles of fontawesome in my project? Here is a glimpse of my work space: https://i.stack.imgur.com/pM1g1.png ...

What is the best way to insert HTML elements in front of other HTML elements using a form and jQuery?

I am looking to insert new HTML elements before existing ones using a form and jQuery: Here is the initial HTML Code: <div class="main-content"> <h2 class="main-content-header">Projekte</h2> <div class="project-content"> ...

Generating unique identifiers for ng-model in AngularJS

Issue - ng-model is not generating dynamically. I have dynamic input boxes and I am attempting to create ng-model dynamically like test[1], test[2], etc. However, when inspecting the form with Firebug, all input elements only show - test[shiftnumber]. HT ...

Alter the Header/Navigation to switch colors depending on the section of the website currently being viewed

I'm currently revamping my personal portfolio website and had an idea for a cool feature. I want the header/navigation bar to change color based on which section of the webpage it's in (the site is one page only). My initial thought was to add o ...

Troubleshooting: Jquery UI Draggable - Cursor losing track of draggable element

I want to create a draggable popup with Jquery UI functionality, but I'm facing an issue where the cursor does not stay aligned with the popup element when dragged. When dragging the popup element to the left, the mouse cursor goes beyond the div elem ...

What is the method for applying multiple criteria to filter an array in Vuejs?

const app = new Vue({ el: '#app', data: { search: '', itemsList: [], isLoaded: false, selectNum: status, userList: [{ id: 1, name: "Prem", status: "ok" }, { id: 2, ...

Unable to observe modifications in json file within java project (jsp)

I am currently using IntelliJ IDEA to develop a web project with JSP. I retrieve data from a file called "customer.json", and when I click on a button, I update this file in the backend. However, after trying to fetch the updated data again, it still reads ...

Is it possible to create a custom options array in React-Select?

I've been working with react-select using the package from . The required format for the options prop is {value:something, label:something}. I have a list of objects with additional key-value pairs and I'm wondering if there's a way to avoi ...

Tips on resolving the issue of an Axios post request not appearing in a get request in React

When using axios to make a post request in this code, a new username is posted, but there is an issue with retrieving the posted name from the API. How can I fix this problem to view my posted request? const App = () => { const [data, setData] = u ...