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
    8853
    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.
    • L
      losika last edited by

      Hello,

      Maybe my question is not really Quasar specific but I did not find any answer till now.

      I want to make my own component from Quasar components. For example I have this in my vue file:

      <q-select filter filter-placeholder="select" :options="[{label: 'a1', value: 'a1'},{label: 'a2', value: 'a2'},{label: 'a3', value: 'a3'}]" v-model="filtera"/>
      <q-select filter filter-placeholder="select" :options="[{label: 'b1', value: 'b1'},{label: 'b2', value: 'b2'},{label: 'b3', value: 'b3'}]" v-model="filterb"/>
      

      As you can see I use two q-select component with different arrays but with the same class definitions (filter and filter-placeholder). I would like to make a new component where these two class style added and I would like to use the new component in my vue like this:

      <m-select :options="[{label: 'a1', value: 'a1'},{label: 'a2', value: 'a2'},{label: 'a3', value: 'a3'}]" v-model="filtera"/>
      <m-select :options="[{label: 'b1', value: 'b1'},{label: 'b2', value: 'b2'},{label: 'b3', value: 'b3'}]" v-model="filterb"/>
      

      So I would write only the difference.

      I tried everything: mixins and extends as well but nothing works. This is my “almost” solution:

      <template>
      <q-select filter filter-placeholder=“select”/>
      </template>

      <script>
      import {
      QSelect
      } from ‘quasar’

      export default {
      name: ‘m-select’,
      components: {
      QSelect
      },
      mixins: [QSelect]
      }
      </script>

      But this is not working because I have warnings that I need to use required props “value” and “options”.

      What is the solution? Is it possible in Vue.js?

      Thanks

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

        I’m sure this is not only possible but very powerful.
        My way of doing this is quite messy so I’m joining my voice to yours, hoping that @rstoenescu will find the time to share a preferred/optimal way of extending quasar locally.
        IMHO this will also help foster more component PRs.

        1 Reply Last reply Reply Quote 1
        • benoitranque
          benoitranque last edited by

          Some kind of @extend single file component would be ideal. Pretty sure Raz already does this internally, so its a matter of learning how it is done…

          The q-side-link is an extension of q-item. From the source, looks like Raz uses Vue mixins. This may be what you are looking for

          1 Reply Last reply Reply Quote 0
          • s.molinari
            s.molinari last edited by

            Yeah, Quasar uses mixins quite a bit.

            Scott

            1 Reply Last reply Reply Quote 0
            • D
              dgk last edited by

              I am in need of making a pin pad component for easy entry of user pins. Seems like it would make use of a combination of existing Quasar components.

              Maybe then some tutorial on using the mixins and/or making deriving “quasar” components from exiting ones.

              I agree if with @spectrolite about the commmunity contributing compenents. As the library of Q components grows Quasar will gain more momentum and thus be able to attract more funding. It’s a win for @rstoenescu to show teach us how to fish.

              1 Reply Last reply Reply Quote 1
              • 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