Reputation: 4885
Think i'm cracking up, this is some very basic stuff but it doesn't seem to be working...
Basically clicking the link should toggle display
between true and false, but this isn't the case.
Vue.component('dropdown', {
props: [ 'expanded' ],
data: function() {
return {
display: !!(this.expanded)
}
},
template: '<div><transition name="expand"><slot :display="display"></slot></transition></div>'
});
window.app = new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{ display }">
<a href="javascript:void(0)" @click="display = !display">Toggle {{ display }}</a>
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
Edit:
Updated code, I forgot I changed that, I did infact have the click event as display = !display
. But even with that said, if you had tried to click the button you would see that it doesn't change the true either...
Upvotes: 0
Views: 209
Reputation: 43881
Updating after a correcting comment from thanksd. I stumbled onto the right answer without really understanding it.
The problem is that within the slot, display
refers to an item in the scope-slot object. Updating it there does not update the actual source variable. If you pass in and call a function, the proper variable is updated.
Vue.component('dropdown', {
props: ['expanded'],
data: function() {
return {
display: Boolean(this.expanded)
}
},
methods: {
toggle() {
this.display = !this.display;
}
},
template: '<div><transition name="expand"><slot :display="display" :toggle="toggle"></slot></transition></div>'
});
new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{display, toggle}">
<a href="javascript:void(0)" @click="toggle">Toggle {{ display }}</a>
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
Upvotes: 4
Reputation: 55644
One solution would be to implement a v-model
for the dropdown
component which would allow you to two-way bind the display
property to a property in the parent. That way you wouldn't need to pass anything via the slot-scope
.
Here's an example of that:
Vue.component('dropdown', {
props: [ 'value' ],
data() {
return {
display: !!(this.value)
}
},
watch: {
value(value) {
this.$emit('input', value);
}
},
template: '<div><transition name="expand"><slot></slot></transition></div>'
});
new Vue({
el: '#app',
data() {
return { dropdownToggle: false }
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown v-model="dropdownToggle">
<div>
<a href="javascript:void(0)" @click="dropdownToggle = !dropdownToggle">
Toggle {{ dropdownToggle }}
</a>
<div v-if="dropdownToggle">
Dropdown content
</div>
</div>
</dropdown>
</div>
Upvotes: 1