From the Vue documentation:
The prop is passed in as a raw value that needs to be transformed. In this case, it's best to define a computed property using the prop's value.
What if this "prop" is array of the objects? I tried to transform it to computed array according documentation. But how to mutate in then?
In below example, component accepts array of items Array<{ ID: string, lettering: string; }>
Array<{ ID: string, lettering: string; }>
. Component renders buttons for each item.
<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 compute the selectableItems
from items
. selectableItems
has property selected
in addition to item
's properties.
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);
}
}
};
Currently, Vue dues not re-render buttons.
I know that the mutate the getter is improper usage. But how I should to mutate the array?
Passing the { ID: string, lettering: string; selected: boolean; }
{ ID: string, lettering: string; selected: boolean; }
{ ID: string, lettering: string; selected: boolean; }
via props
instead of { ID: string, lettering: string; }
{ ID: string, lettering: string; }
is not allowed. { ID: string, lettering: string; }
{ ID: string, lettering: string; }
is pure model, and it must not know about UI. selected: boolean;
is for UI only.
Here's a quick example in a jsfiddle https://jsfiddle.net/hgvajn5t/
As I'm short on time I've skipped creating two components and actually reach down the data as props.
Key is to define your selected buttons in your data
data () {
return {
selectedItems: []
}
},
Second part is to store which items are selected and which aren't
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 recives the item as input and checks if it exists in your selectedItems - if so it will be removed, otherwise it will be added
Final part is to change your binding to set the selected class
:class="{ selected: selectedItems.indexOf(item.ID) > -1 }"
Here again - simply check if it is part of the selectItems
You can then remove your computed property and simply use the props to loop through the elements.
IMPORTANT: This will only work if your item ID values are unique.
Some general thoughts on this: The concept of this can be a bit hard to wrap your head around when you're new to vue, as it seems to be very complicated for simple select states. This might be true for the solution I gave - but overall it highly depends on how you structure your UI in general. The main reason for all this is that you should not manipulate props directly. Using computed props to enhance them is good - manipulating computed props is just as bad. If you need the select state outside your current component you will need to think about using events to emit the click on a button to the parent (where the data comes from) and change the select state directly there. It will then be passed down via props directly. This is the more "natural" way as you manipulate the single source of truth instead of holding additional information about the items in another screen.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.