0

Currently I'm learning VueJS and I'm working with http://vuematerial.io.

I have build an application with several pages - each of them contains a sidebar (the drawer component https://vuematerial.io/components/drawer).

Since I don't want to copy and paste the same drawer component code over and over again in each page, I just want to create one sidebar component, which I'll then import on each page.

So far, so good.

This is working fine.

But now - I want to be able to open and close the sidebar. Just before, when the component was directly in the page, it was easy - just a variable assignment with a boolean value to whether show or hide the sidebar. But now, it seems very hard for me, to synchronize the property over the components.

Let me show you the current new code to clarify what's the problem:

So, this is the page component:

<md-toolbar class="md-primary">
    <md-button class="md-icon-button" @click="showSidebar=true">
        <md-icon>menu</md-icon>
    </md-button><span class="md-title">Dashboard</span>
</md-toolbar>
<Sidebar v-bind:showSidebar="showSidebar"></Sidebar>

So that's the Vue Structure - you can see - I want to bind the showSidebar property. That's how I'm implementing it within the page

import Sidebar from './sidebar.vue';
export default {
    data: function () {
        return {
            showSidebar: false
        }
    },
    components: {
        Sidebar: Sidebar
    },

And now the Sidebar component itself:

<md-drawer v-bind:md-active.sync="showSidebar">

The sidebar component then fetches the value over a property like this:

export default {
    name: 'sidebar',
    props: ['showSidebar'],

And this seems to work! I can click on the menu button on the page, set the property to true - and the sidebar shows! Great! But.. When I click outside of this sidebar, this warn message appears - and - furthermore - I can't reopen it again on a new click. It closes, but I can't open it again, until I completely reload the page.

How can I be able to solve that? I have also thinked about using events, since the drawer component seems to listen on events, but I wasn't successful. That's the current code from the drawer component: https://github.com/vuematerial/vue-material/blob/dev/src/components/MdDrawer/MdDrawer.vue

I hope that it was clear, what my problem is.

I hope, anyone can help me out.

This is my first question here - so please be nice :)

/EDIT: Opps, here is the warn message:

[Vue warn]: 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: "showSidebar"

GPlay97
  • 23
  • 4
  • "this warn message" - what warning message? Think you forgot to paste it in :-) – cjs1978 May 31 '18 at 08:51
  • Thank you @cjs1978 - I've edited it. That's the message: `` [Vue warn]: 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: "showSidebar" `` – GPlay97 May 31 '18 at 08:59
  • It's hard to see from your code where/how you set "showSidebar" to false again (in order to hide it). As for the warn message, check this: https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn – cjs1978 May 31 '18 at 09:03
  • Thank you. The value seems to be set to false directly from the MdDrawer Component itself (take a look at the source code I posted). So, this overwrites my property - and I get this message. Seems logic. What I want to achieve is, that I can open and close the sidebar within the page. The MdDrawer sets the variable to false - so maybe I just need to emit some events to force open or close. The components seems to listen to events (have a look at the soruce please) :) – GPlay97 May 31 '18 at 09:08

1 Answers1

0

I'm not a Vue pro - still learning it myself - but I think I can see what is going on here.

I think the warning in particular is because you have a prop AND a data property of the same name. Try removing the data setting. You can change the props setting to this:

props: {
    showSidebar: {
        type: Boolean,
        default: false
    }
}

See if that fixes it. Also, given how you seem to be using this, I'd suggest looking into using Vuex. The documentation is good and it could really help manage your app. Possibly even fix that issue with reopening the drawer.

Edit:

After reviewing this user's code more closely (connected with them on discord), I've determined the issue is that while the process of opening the sidebar was managed by a property on the parent component, the act of closing it was strictly occurring in the child. When you have data bound like that from parent to child, you need to be sure to update the source (the parent component) of the relevant changes. In Vue, those changes are only pushed one direction. To pass info up to the parent, you have to $.emit events.

My current recommendation is to add a custom event to the sidebar component tag on the parent component:

<Sidebar v-bind:showSidebar="showSidebar" v-on:hide-sidebar="showSidebar=false"></Sidebar>

And then change the close tag in the child component to this:

<span class="md-title" @click="$emit('hide-sidebar')">FleaMaster</span>

Hopefully this information helps someone else as well!

darksnake747
  • 146
  • 1
  • 8