I'm trying to create a component with a 'typeahead' aspect to it and am experiencing some difficulties with it.
There is more to the component than this, but certain actions will trigger the parent component to pass typeaheadItems
to this component, at which point it should display them. The user should have the ability to hide the typeahead though which is where I'm experiencing my problem.
My initial naive approach was as follows.
Attempt 1
Given the Vue component:
<template>
<div
class="typeahead-items"
v-show="myTypeaheadItems.length">
<div class="item close-typeahead">
<i
class="icon close"
@click="closeTypeahead"></i>
</div>
<div
class="item"
v-for="item in typeaheadItems"
:key="item">
{{item}}
</div>
</div>
</template>
<script>
export default {
name: 'typeahead',
props: {
typeaheadItems: {
type: Array,
default: function () {
return [];
}
}
},
data () {
return {
};
},
methods: {
closeTypeahead: function () {
this.typeaheadItems = [];
}
}
};
</script>
This works as expected, showing and hiding appropriately the typeahead, but gives me the warning:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "typeaheadItems"
Attempt 2
I then tried to update the component as follows:
v-for="item in myTypeaheadItems"
data () {
return {
myTypeaheadItems: this.typeaheadItems
};
},
methods: {
closeTypeahead: function () {
this.myTypeaheadItems = [];
}
This doesn't work at all, the typeahead never shows, and there are no warnings or errors.
Attempt 3
Lastly I tried adding a watch:
watch: {
typeaheadItems: function (val) {
this.myTypeaheadItems = val.splice(0);
}
},
This does not work and gives me the warning:
You may have an infinite update loop in watcher with expression "typeaheadItems"
I can't seem to figure out the Vue
way to accomplish this. How can I have an array props coming in from another component and still manipulate it within its own component and have the view update appropriately without warnings/errors?
UPDATE
Upon further review Attempt 2 is the approach that seems like it might be the closest to the 'Vue way' and it is working in that the typeahead items are getting html elements rendered for them, but it appears as though nothing is happening because v-show="myTypeaheadItems.length"
appears to not be updating. I'm not sure why this is the case other than possibly one of the caveats listed on Vue's site.
Given Franco Pino's comments below, I was able to get Attempt 3 to work changing splice
to slice
. Is this the proper way to move forward?