Make own component from Quasar component



  • 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 :slight_smile:



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



  • Thank you @spectrolite :slight_smile:
    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.



  • @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 !



  • 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


  • Admin

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



  • @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. :slight_smile:


  • Admin

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



  • Thanks :slight_smile:
    Will write you as soon as I am back!



  • It works like a charm! Thank you very much.



  • 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?


  • Admin

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


Log in to reply
 

Looks like your connection to Quasar Framework was lost, please wait while we try to reconnect.