How to extend a dialog
-
Hi,
I want to extend a custom dialog component with a slot for its content.
Therefore I have created thisDialogWithSlot.vue
:<template> <q-dialog v-model="visible"> <q-card> <q-card-section> <div class="text-h6">Title</div> </q-card-section> <q-card-section class="q-pt-none"> <slot></slot> </q-card-section> <q-card-actions align="right"> <q-btn flat label="OK" color="primary" v-close-popup/> </q-card-actions> </q-card> </q-dialog> </template> <script> export default { name: 'DialogWithSlot', data() { return { visible: false } }, methods: { showMessage() { this.visible = true } } } </script>
Using this dialog can be done using
<template> <q-page class="flex flex-center"> <!-- This dialog 'dialog-with-slot' approach works, but I want to move it to a seperate component --> <q-btn label="dialog with slot works" @click="openMessage('this is a message')"/> <dialog-with-slot ref="dlg">{{message}}</dialog-with-slot> </q-page> </template> <script> import DialogWithSlot from 'components/DialogWithSlot.vue' export default { name: 'PageInput', data() { return { message: false } }, methods: { openMessage(msg) { this.message = msg this.$refs.dlg.showMessage() } }, components: { DialogWithSlot } } </script>
But now I want to have it in a seperated component file. So I have created this
DialogWithSlotImpl.vue
:<template> <dialog-with-slot>{{messageProp}}</dialog-with-slot> </template> <script> import DialogWithSlot from 'components/DialogWithSlot.vue' export default { name: 'DialogWithSlotImpl', extends: DialogWithSlot, props: ['messageProp'], data() { return {} }, components: { DialogWithSlot } } </script>
and use it like this:
<template> <q-page class="flex flex-center"> <!-- This dialog 'dialog-with-slot-impl' approach don't work, How can I access the method (showMessage()) --> <q-btn label="dialog with slot impl don't work" @click="openMessageImpl('this is yet another message')" /> <dialog-with-slot-impl ref="implDlg" :messageProp="message"/> </q-page> </template> <script> import DialogWithSlotImpl from 'components/DialogWithSlotImpl.vue' export default { name: 'PageInput', data() { return { message: false } }, methods: { openMessageImpl(msg) { this.message = msg this.$refs.implDlg.showMessage() } }, components: { DialogWithSlotImpl } } </script>
But this don’t work. The method showMessage() don’t get called.
A complete codesandbox can be found here.
https://codesandbox.io/s/extending-dialog-6mniuSomebody any idea’s
-
First, you don’t need to add the same component in both
extends
andcomponents
. In your case,extends
is enough.
Second, what you try to achieve is to programmatically setslot
content.You can access the slots of your component through
$slots
.Here, your example with a working solution.
https://codesandbox.io/s/extending-dialog-7960h -
Hi @jraez ,
Your solution does show the dialog. But its content (the message) is missing. So it does not work
-
Hi @jraez
I found a solution of extending templates by using https://github.com/mrodal/vue-inheritance-loader
This solution keeps the template syntax. The root dialog component now looks like:<template extendable> <q-dialog v-model="visible"> <q-card> <q-card-section> <div class="text-h6">Title</div> </q-card-section> <q-card-section class="q-pt-none"> <extension-point></extension-point> </q-card-section> <q-card-actions align="right"> <q-btn flat label="OK" color="primary" v-close-popup /> </q-card-actions> </q-card> </q-dialog> </template> <script> export default { name: 'DialogWithSlot', data () { return { visible: false } }, methods: { showMessage () { this.visible = true } } } </script>
and the child dialog looks like:
<template extends="components/DialogWithSlot.vue"> <extensions> <extension> {{messageProp}} </extension> </extensions> </template> <script> import DialogWithSlot from 'components/DialogWithSlot.vue' export default { name: 'DialogWithSlotImpl', extends: DialogWithSlot, props: ['messageProp'], data () { return { } } } </script>
Looks very easy and straight forward to me.
-
@olaf my bad, was a typo but it works. I misspelled to prop. You can check, it’s working now.
vue-inheritance is the same principle as inheritance in pug. You extend the child template