Joewy Lombe
Joewy Lombe

Reputation: 197

Get chosen date from custom v-date-picker Vuetify

I'm using Vuetify framework for Vue on my current project and I've created a custom component based on the v-date-picker which i plan on using in multiple places. below is the code ;

Child component (custom v-date-picker)

<template>
<v-dialog
        ref="dialog"
        v-model="modal"
        :return-value.sync="date"
        persistent
        width="290px"
      >
        <template v-slot:activator="{ on }">
          <v-text-field
            v-model="date"
            :label=title
            prepend-icon="event"
            readonly
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker v-model="date" scrollable>
          <v-spacer></v-spacer>
          <v-btn text color="primary" @click="modal = false">Cancel</v-btn>
          <v-btn text color="primary" @click="$refs.dialog.save(date)">OK</v-btn>
        </v-date-picker>
      </v-dialog>
</template>
<script>
export default {
    props:[
        'title','date'
    ],
    data () {
      return {
        modal:false,
      }
    },   


}
</script>

Parent Component (Which is a dialog)

<template>
    <v-dialog
      width="800px"
      v-model="dialog"
    >
      <v-card>
        <!-- <v-card-title class="grey darken-2">
          Create contact
        </v-card-title> -->
        <v-container>
          <v-row class="mx-2">

            <v-col cols="3">
              <date-picker-component :date="beginDate" title="Begin Date"></date-picker-component>
            </v-col>
            <v-col cols="3">
              <date-picker-component :date="endDate" title="End Date"></date-picker-component>
            </v-col>
          </v-row>
        </v-container>
        <v-card-actions>
          <v-spacer />
          <v-btn
            text
            color="primary"
            @click="dialog = false"
          >Cancel</v-btn>
          <v-btn
            text
            @click="createEvent"
          >Create Event</v-btn>
        </v-card-actions>
      </v-card>
      <v-overlay :value="overlay">
      <v-progress-circular indeterminate size="64"></v-progress-circular>
    </v-overlay>
    <v-dialog
      v-model="resultDialog"
      max-width="290"
    >
      <v-card>
        <v-card-title class="headline"><v-icon class="pr-2" color="green" st>mdi-check-circle</v-icon> Event Manager</v-card-title>
        <v-card-text>
          {{resultDialogMessage}}
        </v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="green darken-1"
            text
            @click="resultDialog = false"
          >
            OK
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
    </v-dialog>

</template>
<script>
  import Vue from 'vue';
  import DatePicker from "../../widgets/DatePicker";

  export default {
    name: 'CreateEvent',
     props:['dialog'],
    components:{
      'date-picker-component':DatePicker,
    },
    data () {
      return {
        resultDialog:false,
        resultDialogMessage:"",
        overlay:false,
        beginDate:new Date().toISOString().substr(0, 10),
        endDate:new Date().toISOString().substr(0, 10),
      }
    },
  };
</script>

The v-date-picker works fine, but immediately i pick a date, i get the following error in the console;

[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: "date

As a result, I am unable to get the chosen date from the child component and the date just reverts back to the initial date.

Is there something I've left out, what am I doing wrong ?

Upvotes: 1

Views: 4184

Answers (1)

Anees Hameed
Anees Hameed

Reputation: 6544

In vue data to a child, component should be passed as a prop and to the parent component, it should be passed by emitting back. If you use the same variable for passing and emitting value back vue warns you. You need to change your date-picker-component as follows so that prop is not directly getting changed by the child. Instead use a local data.

<template>
<v-dialog
  ref="dialog"
  v-model="modal"
  :return-value.sync="localDate" //Changed here
  persistent
  width="290px"
  >
  <template v-slot:activator="{ on }">
    <v-text-field
      v-model="localDate"  //Changed here
      :label=title
      prepend-icon="event"
      readonly
      v-on="on"
      ></v-text-field>
  </template>
  <v-date-picker v-model="localDate" scrollable>  //Changed here
    <v-spacer></v-spacer>
    <v-btn text color="primary" @click="modal = false">Cancel</v-btn>
    <v-btn text color="primary" @click="$refs.dialog.save(localDate)">OK</v-btn> //Changed here
   </v-date-picker>
</v-dialog>
</template>
<script>
export default {
    props:[
        'title','date'
    ],
    data () {
      return {
        modal:false,,
        localDate: this.date
      }
    },
    watch: {
      localDate(){ 
        this.$emit('update', this.localDate)
      }
    }   
}
</script>

Now in your parent component, you use as follows

<date-picker-component 
  :date="endDate" 
  @update="(v) => (endDate = v)" 
  title="End Date">
</date-picker-component>

Upvotes: 2

Related Questions