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

    Make own component from Quasar component

    Framework
    7
    17
    8326
    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.
    • a47ae
      a47ae last edited by a47ae

      As far as I know, there is no way in Vue.js to really inherit from components, because Vue uses composition over inheritance. One option to write reusable components is mixins. A Mixin is basically a Vue component which is merged into your component. For example, you always want to print out foo bar in a dozen of your components. Instead of manually writing created () => { console.log('foo bar') } in each component you could define a mixin:

      export const FooBarMixin {
        created: function () {
          console.log('foo bar')
        }
      }
      

      And in each of your components you would write the following:

      import FooBarMixin from 'FooBarMixin'
      
      export default {
        // Your normal component stuff
        mixins: [FooBarMixin]
      }
      

      Now your component is merged with the mixin and prints out foo bar.

      But you can’t use mixins to extend the functionality of a whole single file component. If you use a Quasar component as a mixin, all the internal methods and data would be merged into your component, but the template would not. So you had to manually copy the template from that Quasar component into your component, which would not make it update safe.

      But how do you achieve the outcome @losika asked for?
      The solution is simple. Here you do not want to extend a Quasar component, instead, you want to wrap it, to hide some of the implementation details.
      So let’s write such a wrapping component:

      <template>
          <q-select :value="value" :options="options" @change="handleChange" filter filter-placeholder="select"/>
      </template>
      
      <script>
        import { QSelect } from 'quasar'
      
        export default {
          props: ['value', 'options'],
          methods: {
            handleChange (newVal) {
              this.$emit('input', newVal)
            }
          },
          components: {
            QSelect
          }
        }
      </script>
      

      Note that we are passing value to the QSelect component and we are listening for the change event on the QSelect. This is because v-model="foo" is just syntactic sugar for :value="foo" @input="foo = $event.target.value". Also note, that in order to pass additional props that are defined on QInput to the inner component, each of them has to be explicitly defined on the wrapping components and passed to the QInput.

      So often when you just want to use Quasar components to build another component you are using composition and not inheritance. For example @dgk in your example, you do not need to change something on existing components, but you want to build a new component based on Quasar components. So let’s say we build up your pin pad based on QBtn:

      <template>
          <div>
              <div v-for="row in 3" class="row justify-center">
                  <div v-for="col in 3" class="col-auto">
                      <q-btn @click="handleClick((row-1)*3 + col)" :disabled="disabled">
                          {{ (row-1)*3 + col }}
                      </q-btn>
                  </div>
              </div>
          </div>
      </template>
      
      <script>
        import { QBtn } from 'quasar'
      
        export default {
          data () {
            return {
              pin: ''
            }
          },
          methods: {
            handleClick (digit) {
              this.pin += digit
            }
          },
          components: { QBtn }
        }
      </script>
      

      Hopefully, that clarifies a bit when to use mixins and when to just build your component on top of other components. If I am missing something please let me know 🙂

      1 Reply Last reply Reply Quote 8
      • S
        spectrolite last edited by

        I don’t know if this bb allows it, but this last post by @a47ae should be pinned !

        1 Reply Last reply Reply Quote 0
        • a47ae
          a47ae last edited by

          Thank you @spectrolite 🙂
          If I have the time to, I can open up a new topic in the Show&Tell channel where I could post this and also elaborate on some other things like using Stylus variables.

          1 Reply Last reply Reply Quote 1
          • S
            spectrolite last edited by spectrolite

            @a47ae I’m sure @rstoenescu would greatly appreciate it, and most of it would probably end up in the docs at some point.
            Go for it !

            1 Reply Last reply Reply Quote 0
            • a47ae
              a47ae last edited by

              This is still work in progress and I will update this If I have time to, but this should be a good starting point:
              http://forum.quasar-framework.org/topic/696/how-to-building-components-with-quasar

              1 Reply Last reply Reply Quote 2
              • rstoenescu
                rstoenescu Admin last edited by

                @a47ae Let’s make a doc page with this! Want me to create one that you can edit?

                1 Reply Last reply Reply Quote 0
                • a47ae
                  a47ae last edited by

                  @rstoenescu I am really glad that all of you find this guide helpful and would love if this could be added as an official doc page.
                  But I am on vacation until next week, so I do not have time to look into it, but maybe you could already take the existing post and next week I will update it and maybe rewrite some stuff. 🙂

                  1 Reply Last reply Reply Quote 0
                  • rstoenescu
                    rstoenescu Admin last edited by

                    @a47ae enjoy your vacation! sure, please do ping me when you get back so we can get this in.

                    1 Reply Last reply Reply Quote 0
                    • a47ae
                      a47ae last edited by

                      Thanks 🙂
                      Will write you as soon as I am back!

                      1 Reply Last reply Reply Quote 0
                      • L
                        losika last edited by

                        It works like a charm! Thank you very much.

                        1 Reply Last reply Reply Quote 0
                        • L
                          losika last edited by

                          I have to correct myself. I works when the parent component declared as single file component (like QSelect, QBtn, etc. you can see in source code). But if the parent component created in js file (like QList) then it does not work for me. What works is the following:

                          import { QList } from ‘quasar’

                          export default {
                          name: ‘m-list’,
                          mixins: [ QList ],
                          props: {
                          noBorder: { default: true },
                          separator: { default: true }
                          }
                          }

                          It there a better solution for that?

                          And another problem is with refs. a47ae’s solution does not work on QModal. First of all you have to copy methods without that it will complain on ‘open’ mehtods:

                          <template>
                          <q-modal noBackdropDismiss noEscDismiss v-bind:content-css="{width: ‘600px’, height: ‘800px’}"/>
                          </template>

                          <script>
                          import { QModal } from ‘quasar’

                          export default {
                          name: ‘m-modal’,
                          components: { QModal },
                          methods: Object.assign({}, QModal.methods)
                          }
                          </script>

                          But after that the problem is with $refs.content. The error is “Cannot set property ‘scrollTop’ of undefined”. You can see that in QModal’s setTimeout function there is a reference to this.$refs.content what returns undefined. Is there any way to copy refs?

                          1 Reply Last reply Reply Quote 0
                          • rstoenescu
                            rstoenescu Admin last edited by

                            @losika use a mixin instead of declaring QModal as component in your own wrapper.

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