default style



  • @metalsadman Thanks for that. That’s closer to a transparent wrapper than I realized was easily possible. That still leaves out methods, but it’s much less common for me to want to call methods on components anyway, so that’s not a big deal.

    I still prefer my solution of just using the Quasar components directly rather than having to write wrappers for everything though. It seems to me that it would be the rule rather than the exception to want to override the default style props for form components in a consistent way throughout an application. Expecting every app developer to write their own wrapper components to solve this problem seems like a clunky solution, especially since there’s no standardized way to do that, so every developer is going to end up doing it slightly differently.



  • Just to help anyone finding this thread who wants the solution, I just tried @metalsadman’s solution for writing a QInput wrapper. This worked fine for a wrapper that overrides the outlined and dense props but otherwise has the same API as QInput.

    <template>
      <q-input
        v-bind="attrs"
        v-on="$listeners">
        <template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope">
          <slot :name="slot" v-bind="scope"/>
        </template>
      </q-input>
    </template>
    
    <script>
    export default {
      name: 'MyInput',
      computed: {
        attrs () {
          return {
            // Put any prop value overrides here, before the ...this.$attrs line
            outlined: true,
            dense: true,
            ...this.$attrs
          }
        }
      }
    }
    </script>
    


  • It was just pointed out to me in another thread that you can actually extend Vue components instead of wrapping them, which I think solves most of my concerns with wrapping. https://forum.quasar-framework.org/post/21630

    Basically, instead of writing a wrapper like above, use extends like this:

    <script>
    import QInput from 'quasar'
    export default {
      name: 'MyInput',
      extends: QInput
      props: {
        outlined: {
          type: Boolean,
          default: true
        },
        dense: {
          type: Boolean,
          default: true
        }
      }
     }
    </script>
    


  • This Stackoverflow guy says ‘extend’ is a bad idea in Vue ( the last post):

    I’d avoid the “extends” feature of Vue, simply because it is a poorly named method of Vue. It doesn’t really extend anything, not in the case of inheritance. What it does is exactly what the mixin does, it merges the two components together. It has nothing to do with the template code, which isn’t extensible either. The “extend” Vue method should have been called “merge”.

    https://stackoverflow.com/questions/35964116

    Any thoughts?



  • I don’t know how VueJS run under the hood, but what you achieve with extends is more or less the same as adding a mixin to a component.

    The only difference I see is the fact that mixins are abstract components, you never use them as-it. It’s just a fragment. In inheritance, you may found some cases where you instantiate the parent. In the @ajenkins example, you can have QInput and MyInput together on the same app. So it depends on your app, or what you need to achieve, etc. both ways have pros and cons.



  • @dobbel I’m not sure I understand the Stackoverflow guy’s objections. I just tested out extends and it works. It may be true that you can’t “extend” the template code, so it doesn’t exactly correspond to subclassing in an OO language, which seems to be the Stackoverlow guy’s objection, but that seems like a fairly pedantic objection IMO. Extending solves the problem in this case. I just tested this and it works as expected:

    // MyInput.vue
    <script>
    import { QInput } from 'quasar'
    
    export default {
      name: 'MyInput',
      extends: QInput,
      props: {
        outlined: {
          default: true
        },
        dense: {
          default: true
        }
      }
    }
    </script>
    

    I can use my-input just like q-input, and it supports the same props, events, slots, and methods. The only difference is outlined and dense default to true.



  • One slight disadvantage I found with using extends vs the solution I described initially above is that if you’re using an IDE, you lose autocomplete for component props, at least IntelliJ family editors. For example if I do

    <q-input
       err<tab>
    

    The editor will suggest the error-message, error and no-error-icon props, but when using my-input, I don’t get these suggestions. This could work in principle, but the Vue plugin for IntelliJ apparently doesn’t understand extends.



  • I’d use whichever is appropriate, extend or wrapping.



  • This is a valid use case for which a more elegant option from the framework would be helpful.

    For our requirement, we wanted all controls to be flat and bordered, so we went ahead with the following solution:

    // commattribs.js
    export default {
       flat: true,
       bordered: true
    }
    

    then customized individual components that we use to make use of the above attributes:

    <template>
      <q-card
        v-bind="attrs"
        v-on="$listeners"
      >
        <template
          v-for="(_, slot) of $scopedSlots"
          v-slot:[slot]="scope"
        >
          <slot
            :name="slot"
            v-bind="scope"
          />
        </template>
      </q-card>
    </template>
    
    <script>
    import cattribs from './comm-attribs'
    export default {
      name: 'ACard',
      computed: {
        attrs () {
          return {
            ...cattribs,
            ...this.$attrs
          }
        }
      }
    }
    </script>
    

    so if we needed to customize all components with some other attribute, we change them up in commattribs.js



  • But, what if you wanted only some of your components to be a certain way?

    Scott


Log in to reply