Home > front end >  Disabled property in v-for based on prop of component
Disabled property in v-for based on prop of component

Time:05-10

Say I have this:

<v-btn v-for="action in actions" :key="action.icon" :disabled="action.disabled" icon
       @click="action.click(item.id)">
  <v-icon>{{ action.icon }}</v-icon>
</v-btn>

And actions is defined like this:

export default {
  props: {
    rowEditingDisabled: Boolean,
  },
  data() {
    return {
      actions: [
        {icon: 'mdi-pencil', disabled: this.rowEditingDisabled, click: this.edit},
      ],
    };
  },
};

How can I make it so the disabled property is updated when the component prop 'rowEditingDisabled' gets updated?

This is a snippet demonstrating what I mean:

Vue.component('child', {
  template: `
    <div>
      <v-btn :disabled="rowEditingDisabled">This works!</v-btn>
      <v-btn v-for="action in actions" :key="action.icon" :disabled="action.disabled" icon
         @click="action.click(item.id)">
        <v-icon>{{ action.icon }}</v-icon>
      </v-btn>
    </div>`,
  props: {
    rowEditingDisabled: Boolean,
  },
  data() {
    return {
      actions: [
        {icon: 'mdi-pencil', disabled: this.rowEditingDisabled, click: this.edit},
      ],
    };
  },
})
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data() {
    return {
      isDisabled: true
    };
  },
  created() {
    setInterval(() => {
      this.isDisabled = !this.isDisabled;
    }, 1000);
  },
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
  <v-app>
    <v-main>
      <v-container>
        <child :row-editing-disabled="isDisabled"></child>
      </v-container>
    </v-main>
  </v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>

It works when I just use the prop, but when I put it in an array it doesn't work anymore.

CodePudding user response:

Please ensure that you watch the changes in the prop, like this:

export default {
    props: { rowEditingDisabled: Boolean, },
    data() {
        return {
            actions: [{
                icon: 'mdi-pencil',
                disabled: false, 
                click: this.edit
            }], 
        }; 
    },
    watch: { 
        rowEditingDisabled: function(newVal, oldVal) { 
            // watch it
            console.log('Prop changed: ', newVal, ' | was: ', oldVal);
            this.actions[0].disabled = newVal;
        }
    },
};

CodePudding user response:

Try to pass your prop to function:

Vue.component('child', {
  template: `
    <div>
      <v-btn v-for="action in actions" :key="action.icon" :disabled="action.disabledWatch" icon
         @click="action.click(item.id)">
        <v-icon>{{ action.icon }}</v-icon>
      </v-btn>
    </div>`,
  props: {
    rowEditingDisabled: Boolean,
  },
  data() {
    return {
      actions: [
        {icon: 'mdi-pencil', disabledWatch: this.rowEditingDisabled, click: this.edit},
      ],
    };
  },
  watch: {
    rowEditingDisabled(newValue) {
      this.actions[0].disabledWatch = newValue
    }
  }
})
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data() {
    return {
      isDisabled: true
    };
  },
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
  <v-app>
    <v-main>
      <v-container>
        <button @click="isDisabled = !isDisabled">click</button>
        <child :row-editing-disabled="isDisabled"></child>
      </v-container>
    </v-main>
  </v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>

CodePudding user response:

From the data() method, you can reference the component's properties using this.

Can you try this :

data() {
    return {
      actions: [
        {icon: 'mdi-pencil', disabled: this.rowEditingDisabled, click: this.edit},
      ],
    };
  }

Update : Created a working sample code snippet as per my understanding mentioned above and it is working fine. Can you please cross check the naming convention of the props in template, It should be hyphen separated. i.e. :row-editing-disabled="...".

Working Demo :

Vue.component('post', {
  template: '#post-template',
  props: {
    rowEditingDisabled: Boolean
  },
  data() {
    return {
      actions: [
        {icon: 'mdi-pencil', disabled: this.rowEditingDisabled, click: this.edit}
      ]
    };
  }
});

var vm = new Vue({
  el: '#app',
  data: {
    isRowEditingDisabled: true,
  }
});
<script src="https://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>
<div id="app">
  <post :row-editing-disabled="isRowEditingDisabled"></post>
</div>

<template id="post-template">
  <button v-for="action in actions" :key="action.icon" :disabled="action.disabled">
    Click Me!
  </button>
</template>

CodePudding user response:

Sometimes props might be recieved with some delay. In such cases to preserve dynamicity you can make use of computed. Please check the modified lines below

Vue.component('child', {
  template: `
    <div>
      <v-btn v-for="action in actions" :key="action.icon" :disabled="disableRow" @click="action.click(item.id)"> <!-- ***Changes here*** -->
        <v-icon>{{ action.icon }}</v-icon>
      </v-btn>
    </div>`,
  props: {
    rowEditingDisabled: Boolean,
  },
  data() {
    return {
      actions: [
        {icon: 'mdi-pencil', click: this.edit},// ***Changes here***
      ],
    };
  },
 // ***Changes here below***
 computed: {
   disableRow() {
    return this.rowEditingDisabled;
   }
 }
})
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data() {
    return {
      isDisabled: true
    };
  },
  created() {
    // ***Changes here***
    // Commenting the below becoz it changes the flag to false
    /* setInterval(() => {
      this.isDisabled = !this.isDisabled;
    }, 1000); */
  },
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
  <v-app>
    <v-main>
      <v-container>
        <child :row-editing-disabled="isDisabled"></child>
      </v-container>
    </v-main>
  </v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>

  • Related