No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    How to extend a dialog

    Help
    2
    5
    1006
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • O
      olaf last edited by

      Hi,

      I want to extend a custom dialog component with a slot for its content.
      Therefore I have created this DialogWithSlot.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-6mniu

      Somebody any idea’s

      1 Reply Last reply Reply Quote 0
      • J
        jraez last edited by

        First, you don’t need to add the same component in both extends and components. In your case, extends is enough.
        Second, what you try to achieve is to programmatically set slot 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

        1 Reply Last reply Reply Quote 0
        • O
          olaf last edited by

          Hi @jraez ,

          Your solution does show the dialog. But its content (the message) is missing. So it does not work

          1 Reply Last reply Reply Quote 0
          • O
            olaf last edited by

            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.

            1 Reply Last reply Reply Quote 0
            • J
              jraez last edited by

              @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 🙂

              1 Reply Last reply Reply Quote 0
              • First post
                Last post