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

    How to have q-layout-drawer in a seperate component?

    Help
    3
    8
    3018
    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.
    • Z
      Zeitvertreib last edited by Shone

      I want to have my q-layout-drawer decoupled from my Layout.vue file, meaning moving it to a component.
      You can assume the default quasar page of a vanilla quasar project.
      And the modifications concern basic extraction, like so:
      now having following in my Layout.vue file
      under script:

      import sidenav from './../components/q-layoutdrawer-moved-here.vue';
      export default {
        name:'myLayout',
        components: {sidenav},
      	data () {
      		return {
      			leftDrawerOpen: this.$q.platform.is.desktop
      		}
      	},
      

      and in the template

      <sidenav :leftDrawerOpen=leftDrawerOpen/>
      

      which works… poorly
      I get a warning that I should set up a computed proberty, because I am mutating a passed property for the v-model in the q-layout-drawer.
      Also the drawer behaves not as expected I need click the menue button twice after initial loading of the page, before it does what it should do.

      I’m looking for a solution that does not involve using Vuex and/ or that gets rid of the warning in the console. also an eventbus seems to be a more complicated solution, then it should be, but I’m not sure. …also the wierd doubleclick. …or some explaination about the v-model used on the q-layout-drawer, if I missed some easy solution because of my poor understanding of it.

      Might be a lot I ask for, but maybe someone had this already solved.
      I dont find the documentation for using open() on a ref as suggested here but there also was no v-model on q-drawer 2 years ago (I guess).

      1 Reply Last reply Reply Quote 0
      • Z
        Zeitvertreib last edited by

        I found a sufficient solution:
        -> put the q-list in a component (wrap the q-layout-drawer in a v-if element)

        But its just more like a workaround.

        1 Reply Last reply Reply Quote 0
        • G
          genyded last edited by

          Well first of all, we need to see the code for your ‘sidenav’ drawer component too. It sounds like you are not passing a prop to it to toggle it (or an event from the parent). Also we’d need to see the html for it in the parent and the code for the button that toggles it.

          1 Reply Last reply Reply Quote 0
          • Z
            Zeitvertreib last edited by

            This post is deleted!
            1 Reply Last reply Reply Quote 0
            • Z
              Zeitvertreib last edited by

              .sry, not solved. But the system recognized my as spam, so I can’t change the title.
              However, here is the sidenav component:

              <template lang="pug">
                  q-layout-drawer(
                      v-model="leftDrawerOpen"
                      overlay
                      :content-class="$q.theme === 'mat' ? 'bg-grey-2' : null")
              
                    q-list(
                      no-border
                      link
                      inset-delimiter)
                      q-list-header Essential Links
                      q-item(@click.native="openURL('http://quasar-framework.org')")
                        q-item-side(icon="school")
                        q-item-main(label="Docs" sublabel="quasar-framework.org")
              
              </template>
              
              <script>
              import { openURL } from 'quasar'
              
              export default {
                  name: 'sidenav',
                  props: ['leftDrawerOpen'],
                  methods: {
                      openURL
                  }
              }
              </script>
              
              1 Reply Last reply Reply Quote 0
              • G
                genyded last edited by Shone

                Where is the HTML (or PUG) for the sidenav in the layout file?
                Also if you hit F12 in the browser and view the console output, do you see something like:

                Avoid mutating a prop directly since the value will be overwritten whenever the parent
                component re-renders. Instead, use a data or computed property based on the prop's value.
                Prop being mutated: "leftDrawerOpen"
                
                1 Reply Last reply Reply Quote 0
                • G
                  genyded last edited by genyded

                  This post is deleted!
                  1 Reply Last reply Reply Quote 0
                  • S
                    stuartcusack last edited by stuartcusack

                    I experienced a similar problem with q-layout-drawer and I was seeing the Vue warning: ‘Avoid mutating a property directly…’ .

                    As you should know, if you are passing the ‘leftDrawerOpen’ variable down to the child component as a prop then you should avoid manipulating that prop directly in the child component. I was not attempting this in my code but I was still seeing the error.

                    It turns out that q-layout-drawer has a built-in function which detects clicks outside the drawer and attempts to close the itself by updating the v-model ‘leftDrawerOpen’. This works fine when the v-model references data, but when it’s referencing a prop it shows the mutation warning because it’s attempting to manipulate the property.

                    In order to get around this you have to copy the ‘leftDrawerOpen’ prop variable into a local data variable. This means the q-layout-drawer can manipulate the copied data variable without warnings. However, you have to keep in mind that the ‘leftDrawerOpen’ prop could be changed from the parent or from another component, so to keep our local copy up to date you have to watch for changes to that prop.

                    Here is an example:

                    /*CustomDrawerComponent.vue*/
                    /* Passing local data instead of the prop to q-layout-drawer */
                    <q-layout-drawer side="left" v-model="localLeftDrawerOpen">
                        <q-list link inset-delimiter>
                            <q-item to="/">
                                <q-item-side icon="home" />
                                <q-item-main label="Home" sublabel="This is your home" />
                            </q-item>
                        </q-list>
                    </q-layout-drawer>
                    </template>
                    
                    <script>
                    
                    export default {
                    
                        props: {
                            /* this prop gets passed down from our parent - it should NOT be manipulated directly! */
                            leftDrawerOpen: Boolean
                        },
                    
                        data () {
                       
                                return {
                                    /* A local data copy of our prop - which CAN be manipulated here */
                                    localLeftDrawerOpen: false
                        
                                }
                        
                        },
                        
                        watch: {
                            
                            /* If our prop ever gets changed outside of this component then we need to update our local data version of the prop */
                            leftDrawerOpen: function(newVal) {
                                this.localLeftDrawerOpen = newVal;
                            }
                    
                        },
                    
                        mounted: function() {
                    
                            /* As soon as the component is mounted convert our passed prop into data*/
                           /* This line may or may not be necessary - The watch function probably covers it already, but I haven't tested without it yet */
                            this.localLeftDrawerOpen = this.leftDrawerOpen;
                    
                        }
                    
                    }
                    </script>
                    
                    /* Layout */
                    
                    <template>
                    <q-layout>
                    
                        <q-layout-header>
                    
                            <q-toolbar color="primary" :inverted="$q.theme === 'ios'">
                    
                                <q-btn flat dense round @click="leftDrawerOpen = !leftDrawerOpen" aria-label="Menu">
                                    <q-icon name="menu" />
                                </q-btn>
                    
                                <q-toolbar-title>
                                    My Custom App
                                    <div slot="subtitle">Running on Quasar v{{ $q.version }}</div>
                                </q-toolbar-title>
                    
                            </q-toolbar>
                    
                        </q-layout-header>
                    
                        /*passing our parent's data down to our child as a prop*/ 
                        <custom-drawer :left-drawer-open="leftDrawerOpen"></custom-drawer>
                    
                        <!-- this is where the Pages are injected -->
                        <q-page-container>
                    
                            <router-view></router-view>
                    
                        </q-page-container>
                    
                    </q-layout>
                    </template>
                    
                    <script>
                    
                    //Our custom components
                    import CustomDrawer from 'components/CustomDrawer'
                    
                    export default {
                    
                        components: {
                            CustomDrawer 
                        },
                    
                        // name: 'LayoutName',
                        data () {
                            return {
                                leftDrawerOpen: this.$q.platform.is.desktop
                            }
                        },
                    
                        mounted () {
                    
                            var self = this;
                    
                        }
                    }
                    </script>
                    
                    

                    And to go a little further, if you want to keep your header in a separate component then do something like this using Quasar’s global event bus:

                    
                    /*CustomHeader.vue*/
                    /*Emit a request to update the leftDrawerOpen variable*/
                    <q-btn flat dense round @click="$root.$emit('toggle_left_drawer')" aria-label="Menu">
                         <q-icon name="menu" />
                    </q-btn>
                    
                    
                    /*Layout.vue*/
                    mounted () {
                    
                    var self = this;
                    
                    //List for $emits from any child components
                    this.$root.$on('toggle_left_drawer', function() {
                          
                         /* our parent's data is updated, which in turn updates the sidebars props, which in turn updates the sidebars local data - NO WARNINGS :) */
                          self.leftDrawerOpen = !self.leftDrawerOpen;
                    
                     });
                    
                    }
                    
                    ``
                    1 Reply Last reply Reply Quote 1
                    • First post
                      Last post