Configure component prop defaults
-
oh, no, don’t wrap components, extends them.
<script> import QInput from 'quasar' export default { name: 'MyInput', extends: QInput props: { outlined: { type: Boolean, default: true }, dense: { type: Boolean, default: true } } } </script>
Then you have to import MyInput or declare globally and use it instead of QInput. This way you have the default behavior you want, you keep all QInput features and you can even remove outlined or dense manually.
-
@jraez Thank you! I didn’t know about
extend
. That’s exactly what I wanted. -
@jraez that’s amazing. Setting the same property values( like dense outlined ect) for certain q-components is something you do over and over again in every quasar project.
Then why is everybody so focused on a composition solution for this problem (composition has it’s uses but will ‘cripple’ the ‘extended’ component, explained in the posts above) and something simple as extending is never mentioned ( Quasar docs)? Are there some untold cave pits with extending vue/quasar components this way? Just really curious …
-
@ajenkins you’re welcome.
@dobbel Well, it’s only my guess but it’s related to people’s knowledge of OOP, not really quasar or VueJS. After many years of programming, whatever the language, framework, or such, you’ll always land on coding fundamentals
Maybe there’s a downside using inheritance but I’d never face it (in a JS/VueJS/Quasar context).
-
Coz both have their uses, in wrapping you can fiddle with the template, which you cant using extend, unless you want to break it. In this case extend is appropriate since you are just changing the props.
-
For extending my own component template I use pug. I can create the template ‘template’ in parent with block and override what I need in children. The downside is to use 2 files one for Vue component, one for pug template, and include manually the pug into the component each time.
-
@jraez That sounds like a very flexible solution! Would you want to share an example of extending a quasar component with ‘extend’ combined with overriding a part of the parent template with pug?
-
In my case, I use it to create custom QDdialog and inject them through the Dialog plugin. The idea is to have a standard design with an icon + title, some action buttons, and the content.
I changed the ProductDialog to something out of my own scope because it’ll be too complex for an example.
The base dialog
<script> export default { props: ['name'], data: () => ({ config: { title: '', position: 'standard', translateTitle: true, cssClass: 'custom-dialog', icon: 'fas fa-exclamation-triangle' } }), methods: { // following method is REQUIRED // (don't change its name --> "show") show () { this.$refs.dialog.show() }, // following method is REQUIRED // (don't change its name --> "hide") hide () { this.$refs.dialog.hide() }, onDialogHide () { // required to be emitted // when QDialog emits "hide" event this.$emit('hide') }, onOKClick () { // on OK, it is REQUIRED to // emit "ok" event (with optional payload) // before hiding the QDialog this.$emit('ok') // or with payload: this.$emit('ok', { ... }) // then hiding dialog this.hide() }, onCancelClick () { // we just need to hide dialog this.hide() } } } </script> <style> .custom-dialog { width: 600px; } </style>
The dialog template:
q-dialog(ref="dialog" @hide="onDialogHide" :persistent="true" :position="config.position") q-card(:class="config.cssClass") block wrapper block title q-card-section.row.items-center.text-h4 q-icon(:name="config.icon").q-mr-md .text-capitalize {{ config.translateTitle ? $t(config.title) : config.title}} q-space q-icon(@click="onCancelClick" name="fas fa-times").cursor-pointer.q-ml-md block separator q-separator(inset) q-card-section(:horizontal="config.horizontal") block content q-card-actions.justify-end block actions q-btn(color="primary" flat :label="$t('application.actions.cancel')" @click="onCancelClick") q-btn(color="primary" :text-color="$theme.colors.primaryText" :label="$t('application.actions.save')" @click="onOKClick")
The my dialog implement:
<template lang="pug"> extends ../../UI/Dialog/DialogBase block content q-card-section.col-4 .text-body2 {{ $t('application.product.list') }} q-scroll-area(style="height: 700px;") q-list.q-mt-md q-item(v-for="product in products" :key="product.id" dense) q-item-section(side) q-btn(flat round icon="fas fa-times" @click="remove(product)") q-item-section(side) q-btn(flat round icon="fas fa-edit" @click="edit(product)") q-separator(vertical) q-card-section.col .text-body2.q-mb-sm {{ $t('application.product.info') }} .row.q-gutter-none q-editor(v-model="product.description") block actions q-btn(color="primary" flat :label="$t('application.actions.reset')" @click="reset") q-btn(color="primary" :text-color="$theme.colors.primaryText" :label="$t('application.actions.save')" @click="save") </template> <script> import DialogBase from '../../UI/Dialog/DialogBase' export default { name: 'ProductManagerDialog', extends: DialogBase, data: () => ({ config: { title: 'application.product.manager.title', cssClass: 'project-product-manager', icon: 'fas fa-calendar-alt', horizontal: true }, products: [] product: null }), methods: { edit (product) { this.product = product }, async remove (product) { // remove product from products and save to the backend } }, async mounted () { this.products = await ProductService.list() } } </script> <style> .project-product-manager { min-width: 1100px; } </style>
-
@jraez Thanks for the sample code. Do you like to use Pug to code (Quasar templates) or is it necessary because your want to override templates?
-
@dobbel I use pug because it makes the template more readable to me (less “verbose” in fact), so I’ve started using it before the need to override templates. Then it helps me with overriding and composition, so I stick to it.
-
@jraez Tried extending QInput but I’m getting this error:
Failed to mount component: template or render function not defined.Tried copy pasting your example but I get the same error
MyInput.vue
<script> import QInput from 'quasar' export default { name: 'MyInput', extends: QInput, props: { outlined: { type: Boolean, default: true }, dense: { type: Boolean, default: true } } } </script>
Page.vue
<template> <div> <my-input></my-input> </div> </template> <script> import MyInput from 'components/MyInput' export default { components: { MyInput }, name: 'PageIndex' } </script>
Am I doing it wrong?
-
Nvm. I was just missing the curly brace
<script> import { QInput } from 'quasar' export default { name: 'MyInput', extends: QInput, props: { outlined: { type: Boolean, default: true }, dense: { type: Boolean, default: true } } } </script>
-
I’ve started a quasar extension for this purpose. At the time of typing it only has a QBtn extension to prove the concept but will continue to add other components that have styling properties. Check it out and submit an issue of the component you want added so I can prioritise them. Or fork it and create a pull request with the component you want. It isn’t hard to extend a component just check out the code for QBtn
https://github.com/garhbod/quas-tom
https://www.npmjs.com/package/quasar-app-extension-quas-tom -
Nice! You should create a post in
Show and Tell
on this forum for bigger audience. -
This post is deleted!