admin管理员组

文章数量:1325236

I need to use Vuetify v-date-picker in different ponents. But that will lead to code duplication. So I thought it will be interesting to create a custom <custom-date-picker /> ponent which I can use anywhere I need to.

  • This child ponent should emit to the parent the value of the formatted date.
  • The parent ponent has a button which console logs the formatted date

But with my current code, I am getting this error message:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent ponent re-renders. Instead, use a data or puted property based on the prop's value. Prop being mutated: "value"

found in

---> <CustomDatePicker> at ponents/CustomDatePicker.vue
       <Pages/index.vue> at pages/index.vue

Parent ponent is pages/index.vue:

<template>
  <div>
    <custom-date-picker v-model="date" />
    <v-btn @click="getDate">
      Ok
    </v-btn>
  </div>
</template>

<script>
import CustomDatePicker from '@/ponents/CustomDatePicker.vue'

export default {
  ponents: { CustomDatePicker },
  data () {
    return {
      date: ''
    }
  },
  methods: {
    getDate () {
      console.log(this.date)
    }
  }
}
</script>

Child ponent is ponents/CustomDatePicker.vue:

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-bind:value="value"
              v-on:input="$emit('input', $event)"
              @blur="date = parseDate(value)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-model="date"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null
    }
  },

  puted: {
    putedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.value = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>

How to overe my issue ?

This simple demo is available on Github if you have time for it :)

UPDATE 1:

I succeeded to get rid of the error message above by avoiding mutating the prop value. I can choose the date and when I click on the Ok button I get the date console logged properly.

The issue is that the text field of the parent ponent does not show the date I picked, it stays as it is shown on the picture above.

Here is the updated code of the child ponent:

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-model="dateFormatted"
              @blur="date = parseDate(dateFormatted)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-bind:value="value"
            v-on:input="$emit('input', $event)"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null,
      dateFormatted: null
    }
  },

  puted: {
    putedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.dateFormatted = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>

I need to use Vuetify v-date-picker in different ponents. But that will lead to code duplication. So I thought it will be interesting to create a custom <custom-date-picker /> ponent which I can use anywhere I need to.

  • This child ponent should emit to the parent the value of the formatted date.
  • The parent ponent has a button which console logs the formatted date

But with my current code, I am getting this error message:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent ponent re-renders. Instead, use a data or puted property based on the prop's value. Prop being mutated: "value"

found in

---> <CustomDatePicker> at ponents/CustomDatePicker.vue
       <Pages/index.vue> at pages/index.vue

Parent ponent is pages/index.vue:

<template>
  <div>
    <custom-date-picker v-model="date" />
    <v-btn @click="getDate">
      Ok
    </v-btn>
  </div>
</template>

<script>
import CustomDatePicker from '@/ponents/CustomDatePicker.vue'

export default {
  ponents: { CustomDatePicker },
  data () {
    return {
      date: ''
    }
  },
  methods: {
    getDate () {
      console.log(this.date)
    }
  }
}
</script>

Child ponent is ponents/CustomDatePicker.vue:

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-bind:value="value"
              v-on:input="$emit('input', $event)"
              @blur="date = parseDate(value)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-model="date"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null
    }
  },

  puted: {
    putedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.value = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>

How to overe my issue ?

This simple demo is available on Github if you have time for it :)

UPDATE 1:

I succeeded to get rid of the error message above by avoiding mutating the prop value. I can choose the date and when I click on the Ok button I get the date console logged properly.

The issue is that the text field of the parent ponent does not show the date I picked, it stays as it is shown on the picture above.

Here is the updated code of the child ponent:

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-model="dateFormatted"
              @blur="date = parseDate(dateFormatted)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-bind:value="value"
            v-on:input="$emit('input', $event)"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null,
      dateFormatted: null
    }
  },

  puted: {
    putedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.dateFormatted = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>
Share Improve this question edited Dec 19, 2019 at 7:41 Billal BEGUERADJ asked Dec 19, 2019 at 6:42 Billal BEGUERADJBillal BEGUERADJ 22.8k45 gold badges123 silver badges140 bronze badges 5
  • How to overe my issue ... I'd suggest you Avoid mutating a prop directly and Instead, use a data or puted property based on the prop's value – Jaromanda X Commented Dec 19, 2019 at 7:23
  • Thank you, that is exactly what I avoided now (after I posted the question), I get the chosen date when I clock on the button, but it is not reflected on the text field for the moment (it stays as it is on the picture) @JaromandaX – Billal BEGUERADJ Commented Dec 19, 2019 at 7:34
  • Did you post the new code @JaromandaX ? – Jesper Commented Dec 19, 2019 at 7:38
  • I updated my post with relevant code and explanation. @Djip – Billal BEGUERADJ Commented Dec 19, 2019 at 7:42
  • I updated my question with half working code @JaromandaX – Billal BEGUERADJ Commented Dec 19, 2019 at 7:43
Add a ment  | 

1 Answer 1

Reset to default 6

Changes i've made to get it to work, is that i've added a puted with a get() and set(). The getter will return the current selected value, and the setter will be emitting the new value each time it's changing.

This is a good way of utilizing the v-model within custom ponents.

CustomDatePicker.vue

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-model="selected"
              v-on:input="$emit('input', $event)"
              @blur="date = parseDate(value)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-model="selected"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
  export default {
    name: 'CustomDatePicker',
    props: {
      value: {
        type: String,
        default: ''
      }
    },
    data () {
      return {
        menu1: null,
        date: null
      }
    },

    puted: {
      selected: {
        get() {
          return this.value
        },
        set(value) {
          this.$emit('input', value)
        }
      },
      putedDateFormatted () {
        return this.formatDate(this.date)
      }
    },

    watch: {
      date (val) {
        this.value = this.formatDate(this.date)
      }
    },
    methods: {
      formatDate (date) {
        if (!date) { return null }
        return date
      },
      parseDate (date) {
        if (!date) { return null }

        const [year, month, day] = date.split('-')
        return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
      }
    }
  }
</script>

本文标签: javascriptCustom date picker in VuetifyStack Overflow