Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to bind props to v-model

I am using vuetify.js and trying to create a component which can be reusable across the application. Although its working absolutely fine, but I am not sure if it's the correct way.

I am creating a navigation drawer component which has the same menu options all the time but it can be opened from UI elements.

Below is the code.

// NavigationBar.vue

<template>
  <v-navigation-drawer
    temporary
    v-model="drawerFlag"
    light
    overflow
    fixed
  >
    <v-list>
      <v-list-tile>
        <v-list-tile-action @click.stop="toggleDrawer()">
          <v-btn icon>
            <v-icon>close</v-icon>
          </v-btn>
        </v-list-tile-action>
      </v-list-tile>
    </v-list>
    <v-list class="pt-0">
      <template v-for="item in items">
        <v-list-tile :key="item.title" :to="item.link">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
        <v-divider></v-divider>
      </template>
    </v-list>
  </v-navigation-drawer>
</template>

<script>
  export default {
    props: ['drawer'],
    data() {
      return {
        items: [
          { title: 'Home', icon: 'home', link: '/home'},
          { title: 'History', icon: 'history', link: '/history' },
          { title: 'Wallet', icon: 'account_balance_wallet', link: '/wallet' },
          { title: 'My Profile', icon: 'person', link: '/profile' },
          { title: 'Settings', icon: 'settings', link: '/settings' },
          { title: 'About', icon: 'error', link: '/about' },
          { title: 'Logout', icon: 'power_settings_new', link: '/logout' },
        ]
      };
    },
    computed: {
      drawerFlag: {
        get: function() {
          return this.drawer
        },
        set: function() {

        }
      }
    },
    methods: {
      toggleDrawer: function() {
        this.$emit('emitToggleDrawer');
      }
    }
  }
</script>

//Home.vue

<template>
  <div class="full-screen">
    <navigation-bar :drawer="drawer" v-on:emitToggleDrawer="toggleDrawer"></navigation-bar>
    <v-btn icon class="mt-3 fixed-position" @click.stop="drawer = !drawer">
      <v-icon>menu</v-icon>
    </v-btn>
  </div>
</template>

<script>
  export default {
    name: 'home',
    data() {
      return {
        drawer: null
      };
    },

    computed: {
      user() {
        return this.$store.getters.user;
      }

    },

    methods: {
      toggleDrawer: function () {
        this.drawer = !this.drawer;
      }
    }
  };
</script>

In the above code..

In parent component, I have button to open navigation-drawer and the state of the navigation drawer is maintained in the parent component called "drawer". Then, I am passing "drawer" as a prop to child component and a method to trigger an event from child component to parent component called "emitToggleDrawer".

In child component, I am using vuetify.js navigation-drawer which takes v-model="drawerFlag", where drawerFlag is a computed property. When i tried to use v-model="drawer" i.e. binding to the prop I was getting an error. Then we can close the navigation drawer by clicking an element inside the navigation-drawer. To achieve that, I am calling a method of the component which later on emits an event which is listened by parent component.

like image 417
Arpit Avatar asked Sep 26 '17 08:09

Arpit


People also ask

Can I use Props in v-model?

To let our component support v-model two-way binding, the component needs to accept a value prop and emit an input event. To support v-model , the component accepts a value prop and emits an input event.

How does the V-bind works?

The v-bind directive is a Vuejs directive used to bind one or more attributes, or a component prop to an element. If that attribute is binded to our data defined in Vuejs instance then dynamically changes can be observed as data changes.

What is the difference between v-model and V-bind?

In simple words v-model is for two way bindings means: if you change input value, the bound data will be changed and vice versa. but v-bind:value is called one way binding that means: you can change input value by changing bound data but you can't change bound data by changing input value through the element.

Is V-bind two way?

The v-model directive makes two-way binding between a form input and app state very easy to implement. One can bind a form input element and make it change the Vue data property when the content of the field changes.


1 Answers

I solved it like this:

App.vue

<my-drawer ref="drawer"></my-drawer>
<my-header @toggle-drawer="$refs.drawer.drawer = !$refs.drawer.drawer"></my-header>

MyDrawer.vue

<v-navigation-drawer v-model="drawer">
...
data() {
  drawer: true
}

MyHeader.vue

<v-toolbar-side-icon @click.stop="$emit('toggle-drawer')"></v-toolbar-side-icon>


It seems to me that we need v-model="drawer" on custom drawer component so it can properly work on all screen sizes.

Thus we need to change it's value from parent (or sibling) somehow also, that's why I'm using ref on drawer component. Maybe instead of changing $refs.drawer.drawer data I could call drawers functions instead. I'm not sure what would be better approach. But this was the only simple solution that worked for me on all screen sizes.

So in my case, I'm changing drawer state only from header, but I think you can use this and fit according to your needs.

like image 200
Traxo Avatar answered Sep 28 '22 09:09

Traxo