Vuetify's personalized date selection tool

Utilizing Vuetify's v-date-picker in multiple components can result in code repetition. To address this, I decided to create a custom <custom-date-picker /> component that can be used wherever needed.

  • This child component should emit the formatted date value to the parent.
  • The parent component contains a button that logs the formatted date to the console.

https://i.sstatic.net/AxVM8.png

However, I encountered an error message with my current code:

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

found in

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

The parent component is located in pages/index.vue:

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

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

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

The child component is located in components/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
    }
  },

  computed: {
    computedDateFormatted () {
      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 can I resolve this issue?

A basic demo of this setup is available on Github if you wish to explore further :)

UPDATE 1:

I have managed to eliminate the previous error message by avoiding direct mutation of the prop value. Now, I can select a date and upon clicking the Ok button it correctly logs the selected date. However, the text field in the parent component does not display the chosen date as illustrated in the image above.

Below is the updated code for the child component:

<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
    }
  },

  computed: {
    computedDateFormatted () {
      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>

Answer №1

One of the key changes I implemented to make it functional was adding a computed property with both get() and set() methods. The getter retrieves the current selected value, while the setter emits the new value whenever there is a change.

This approach effectively leverages the v-model feature within custom components.

The code snippet below demonstrates the implementation in 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
      }
    },

    computed: {
      selected: {
        get() {
          return this.value
        },
        set(value) {
          this.$emit('input', value)
        }
      },
      computedDateFormatted () {
        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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

XMLHTTPRequest is experiencing issues with displaying the progress bar

I'm facing an issue with uploading images in PHP while showing the progress status. The image uploads correctly using XMLHttpRequest, but I can't see the progress bar moving. Below is my code. Can someone help me solve this problem? <html> ...

Triggering of NVD3 Angular Directive callback occurring prematurely

Lately, I've delved into utilizing NVD3's impressive angular directives for crafting D3 charts. They certainly have a sleek design. However, I'm encountering numerous challenges with callbacks. While callbacks function smoothly when incorpor ...

Combining several meshes in ThreeJS while maintaining distinct materials

I seem to be facing a dilemma. I am attempting to consolidate several meshes into one in order to optimize draw calls. Each mesh I have comes with its own unique material, whether it be color or texture. Below is the snippet of code I have been working on ...

I'm trying to retrieve information from openweathermap in order to show it on my app, but I keep running into an error that says "Uncaught RangeError: Maximum

I recently created a div with the id 'temporary' in order to display data retrieved from the openweathermap.org API. However, I am encountering an error in the console and I'm not sure why. This is my first time working with APIs and I would ...

Is there a way to trigger a function in an AngularJS controller from a Backbone controller?

I've been working on an application that was originally developed using backbone and jQuery, but we had to incorporate new modules built with angular to meet client requirements. Routing in the application is handled by backbone route, and we have suc ...

What is the best way to remove the left margin from a MuiTreeItem-group?

I'm working with the MUI tree component and I want to remove the left margin of the second layer of MuiTreeItem-group I attempted to use makeStyles to address this issue, but it didn't have the desired effect const useStyles = makeStyles(() => ...

Retrieve JavaScript Variable Value when Button is Clicked via asp:HiddenField

Having limited experience with JavaScript and jQuery, I decided to make some modifications to a jQuery Slider for adjusting dates. You can check out what I've done so far here: http://jsfiddle.net/ryn_90/Tq7xK/6/. I managed to get the slider working ...

HTML Navigator encountering Javascript Anomaly

Here is the code snippet I'm working with: driver = new HtmlUnitDriver(); ((HtmlUnitDriver) driver).setJavascriptEnabled(true); baseUrl = "http://www.url.com/"; driver.get(baseUrl + "/"); ... However, whenever I ...

issue encountered during resource provider setup

Below is my code snippet where I'm attempting to populate a table using ngResource in a RESTful manner. However, when I include configuration directives, I encounter an uncaught object MINERR ASST:22 error. var app = angular.module('infra&apo ...

Tips on passing methods to form provider with unique name for managing nested forms

As discussed in #60277873, when creating nested forms, it is necessary to rename the methods of the nested form as follows: const { register, formState: { errors }, handleSubmit, } = useForm({ mode: "onBlur", }); This code sh ...

Attributes for 'v-bind' directives must have a value specified

Struggling to implement a tree structure in vue.js and encountering an issue with element props. Any assistance would be greatly appreciated. I've attempted using :content="{{tempCont}}" as well as content="{{tempCont}}", but neither approach proved ...

Database not receiving input data from AngularJS form submission

Having some trouble saving form data to the database using angularjs. Not sure what I'm doing wrong. Here's my HTML form: <form id="challenge_form" class="row" > <input type="text" placeholder="Challenge Name" ng-model="ch ...

What is the best way to incorporate Vuetify into a new application?

Recently, I developed a new app using Vue and I decided to integrate Vuetify as the framework. After executing the npm install vuetify --save command, Vuetify was added to the app successfully. However, when I tried to use it, the CSS button colors were no ...

What could be the reason for the error message when using rs.send with a string input?

I'm a beginner in node and express, and I was trying to create an HTML form that takes two numbers and displays the result using "express" and "node". However, when I use rs.send(result), I encounter the following error: https://i.sstatic.net/FcUNJ.p ...

React router will only replace the last route when using history.push

I'm working on implementing a redirect in React Router that triggers after a specific amount of time has elapsed. Here's the code I've written so far: submitActivity(){ axios.post('/tiles', { activityDate:thi ...

Undefined Children Component

I am currently working on creating Auth routes and I am facing an issue where the children are undefined, resulting in a blank page. In my App.js file, I have implemented a PrivateRoute component as shown below. Interestingly, when I replace PrivateRoute w ...

Clipped Words & Silhouettes

I'm having trouble ensuring the text in this particular example displays correctly. I am experiencing challenges with the clipping of text and shadows on certain letters, and I'm struggling to identify the root cause as well as the solution. In ...

The DOM does not contain unscrolled rows in the DataTable's infinite scrolling feature

Every time I create a dataTable with infinite scrolling, I use the following code: $('#table1').dataTable({ 'aaData' : dataArr, 'aoColumns': columnArr, 'bScrollInfinite': true, 'bColumnCollapse& ...

Is it possible to attach React Components to Elements without using JSX?

In my React Component, I have the following code: import React, { useEffect } from 'react' import styles from './_PhotoCollage.module.scss' import PhotoCard from '../PhotoCard' const PhotoCollage = ({ author }) => { let ...

Ways to detect events even after the object has been swapped out in JavaScript

I am currently developing a JavaScript-based Scrabble game and encountering a puzzling issue. The problem arises when tiles are generated within a tile rack div using a specific function, and an event listener is set up to respond to clicks on the tile div ...