Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date input without time, persistent dialog, ISO Format #85

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,19 @@ Once installed, it can be used in a template as simply as:
| datetime (model) | Date/String | | Time picker model. |
| disabled | Boolean | false | Input is disabled. |
| loading | Boolean | false | Input is loading. |
| persistent | Boolean | false | Clicking outside of the picker will not close it. |
| label | string | | Sets input label. |
| dialogWidth | Number | 340 | The width of the dialog. |
| dateFormat | string | yyyy-MM-dd | Defines the format of a date. |
| timeFormat | string | HH:mm | Defines the format of a time. |
| clearText | string | CLEAR | Sets the text of the clear button. |
| clearText | string | CLEAR | Sets the text of the clear button. An empty string prevents the button from showing. |
| cancelText | string | | Sets the text of the cancel button. An empty string prevents the button from showing. Click on it resets datetime to value before opening the picker. |
| okText | string | OK | Sets the text of the ok button. |
| textFieldProps | Object | | Text fields properties. See [Vuetify Docs](https://vuetifyjs.com/en/components/text-fields 'Vuetify Docs') |
| datePickerProps | Object | | Date pickers properties.See [Vuetify Docs](https://vuetifyjs.com/en/components/date-pickers 'Vuetify Docs') |
| timePickerProps | Object | | Time pickers properties.See [Vuetify Docs](https://vuetifyjs.com/en/components/time-pickers 'Vuetify Docs') |
| useIso | Boolean | false | Use ISO format in datetime (model) and input event |
| withoutTime | Boolean | false | Pick a date without a time. |

## Events

Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "DatetimePicker component for Vuetify.js.",
"main": "src/index.js",
"scripts": {
"start": "npm run dev",
"dev": "webpack-dev-server --config webpack/webpack.dev.config.js",
"build": "webpack --config webpack/webpack.build.config.js --progress --profile --colors",
"deploy": "npm run build && npm publish --registry https://registry.npmjs.org/",
Expand Down Expand Up @@ -51,8 +52,8 @@
"webpack-merge": "^4.2.1"
},
"dependencies": {
"date-fns": "^2.1.0",
"vue": "^2.6.10",
"vuetify": "^2.1.3"
"date-fns": "^2.16.1",
"vue": "^2.6.12",
"vuetify": "^2.3.13"
}
}
110 changes: 110 additions & 0 deletions src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,46 @@
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with Date without Time</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="dateWithoutTime" without-time></v-datetime-picker>
</v-flex>
<div>Date value: <span v-text="dateWithoutTime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with Date without Clear Button</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="datetime" clear-text=""></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="datetime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with Date without Cancel Button</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="datetime" cancelText=""></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="datetime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with Date (persistent)</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="datetime" persistent></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="datetime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with String</v-expansion-panel-header>
<v-expansion-panel-content>
Expand All @@ -40,6 +80,16 @@
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Init with String without Time</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="dateStringWithoutTime" without-time></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="dateStringWithoutTime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Loading</v-expansion-panel-header>
<v-expansion-panel-content>
Expand Down Expand Up @@ -114,6 +164,19 @@
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Custom Validation (Input Required)</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-form v-model="validForm">
<v-datetime-picker v-model="nullDatetime" :textFieldProps="textFieldPropsRules"></v-datetime-picker>
</v-form>
</v-flex>
<div>Datetime value: <span v-text="nullDatetime"></span></div>
<div>Valid Form: <span v-text="validForm"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Use Seconds</v-expansion-panel-header>
<v-expansion-panel-content>
Expand Down Expand Up @@ -145,6 +208,38 @@
<div>Datetime value: <span v-text="datetime"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Custom Format: ISO</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker v-model="datetimeStringISO" use-iso ></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="datetimeStringISO"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

<v-expansion-panel>
<v-expansion-panel-header>Custom Property and Format: German date and time format, ISO</v-expansion-panel-header>
<v-expansion-panel-content>
<v-flex xs4>
<v-datetime-picker
v-model="datetimeStringISO"
use-iso
label="Tag und Zeit"
date-format="dd.MM.yyyy"
time-format="HH:mm"
ok-text="Speichern"
clear-text="Löschen"
cancel-text="Abbrechen"
:date-picker-props="datePropsDe"
:time-picker-props="timePropsDe"
></v-datetime-picker>
</v-flex>
<div>Datetime value: <span v-text="datetimeStringISO"></span></div>
</v-expansion-panel-content>
</v-expansion-panel>

</v-expansion-panels>
</v-row>
</v-container>
Expand All @@ -157,19 +252,34 @@ import '@fortawesome/fontawesome-free/css/all.css'
export default {
data() {
return {
validForm: false,
nullDatetime: null,
datetime: new Date(),
dateWithoutTime: new Date(),
datetimeString: '2019-01-01 12:00',
datetimeStringISO: '2019-01-01T11:00:00.000Z',
dateStringWithoutTime: '2019-01-01',
formattedDatetime: '09/01/2019 12:00',
textFieldProps: {
appendIcon: 'event'
},
textFieldPropsRules: {
rules: [v => !!v || 'Date is required']
},
dateProps: {
headerColor: 'red'
},
timeProps: {
useSeconds: true,
ampmInTitle: true
},
datePropsDe: {
locale: 'de-de',
firstDayOfWeek: 1
},
timePropsDe: {
locale: 'de-de',
format: '24hr'
}
}
}
Expand Down
56 changes: 49 additions & 7 deletions src/components/DatetimePicker.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-dialog v-model="display" :width="dialogWidth">
<v-dialog v-model="display" :width="dialogWidth" :persistent="persistent" @click:outside="outsiteHandler" @keydown.esc="outsiteHandler">
<template v-slot:activator="{ on }">
<v-text-field
v-bind="textFieldProps"
Expand All @@ -20,7 +20,7 @@

<v-card>
<v-card-text class="px-0 py-0">
<v-tabs fixed-tabs v-model="activeTab">
<v-tabs fixed-tabs v-model="activeTab" v-if="!withoutTime">
<v-tab key="calendar">
<slot name="dateIcon">
<v-icon>event</v-icon>
Expand All @@ -44,20 +44,28 @@
></v-time-picker>
</v-tab-item>
</v-tabs>
<v-date-picker
v-if="withoutTime"
v-model="date"
v-bind="datePickerProps"
@input="showTimePicker"
full-width
></v-date-picker>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<slot name="actions" :parent="this">
<v-btn color="grey lighten-1" text @click.native="clearHandler">{{ clearText }}</v-btn>
<v-btn color="grey lighten-1" text @click.native="clearHandler" v-if="clearText.length > 0">{{ clearText }}</v-btn>
<v-btn color="green darken-1" text @click="okHandler">{{ okText }}</v-btn>
<v-btn color="grey lighten-1" text @click.native="cancelHandler" v-if="cancelText.length > 0">{{ cancelText }}</v-btn>
</slot>
</v-card-actions>
</v-card>
</v-dialog>
</template>

<script>
import { format, parse } from 'date-fns'
import { format, parse, parseISO } from 'date-fns'

const DEFAULT_DATE = ''
const DEFAULT_TIME = '00:00:00'
Expand All @@ -66,6 +74,7 @@ const DEFAULT_TIME_FORMAT = 'HH:mm:ss'
const DEFAULT_DIALOG_WIDTH = 340
const DEFAULT_CLEAR_TEXT = 'CLEAR'
const DEFAULT_OK_TEXT = 'OK'
const DEFAULT_CANCEL_TEXT = 'CANCEL'

export default {
name: 'v-datetime-picker',
Expand All @@ -84,6 +93,10 @@ export default {
loading: {
type: Boolean
},
persistent: {
type: Boolean,
default: false
},
label: {
type: String,
default: ''
Expand All @@ -108,6 +121,10 @@ export default {
type: String,
default: DEFAULT_OK_TEXT
},
cancelText: {
type: String,
default: DEFAULT_CANCEL_TEXT
},
textFieldProps: {
type: Object
},
Expand All @@ -116,6 +133,14 @@ export default {
},
timePickerProps: {
type: Object
},
useIso: {
type: Boolean,
default: false
},
withoutTime: {
type: Boolean,
default: false
}
},
data() {
Expand All @@ -131,7 +156,7 @@ export default {
},
computed: {
dateTimeFormat() {
return this.dateFormat + ' ' + this.timeFormat
return this.withoutTime ? this.dateFormat : this.dateFormat + ' ' + this.timeFormat
},
defaultDateTimeFormat() {
return DEFAULT_DATE_FORMAT + ' ' + DEFAULT_TIME_FORMAT
Expand All @@ -157,6 +182,8 @@ export default {
methods: {
init() {
if (!this.datetime) {
this.date = DEFAULT_DATE
this.time = DEFAULT_TIME
return
}

Expand All @@ -165,22 +192,37 @@ export default {
initDateTime = this.datetime
} else if (typeof this.datetime === 'string' || this.datetime instanceof String) {
// see https://stackoverflow.com/a/9436948
initDateTime = parse(this.datetime, this.dateTimeFormat, new Date())
initDateTime = this.useIso ? parseISO(this.datetime) : parse(this.datetime, this.dateTimeFormat, new Date())
}

if (this.withoutTime) {
initDateTime.setHours(0, 0, 0, 0)
}

this.date = format(initDateTime, DEFAULT_DATE_FORMAT)
this.time = format(initDateTime, DEFAULT_TIME_FORMAT)
},
okHandler() {
this.resetPicker()
this.$emit('input', this.selectedDatetime)
return this.useIso
? this.$emit('input', this.selectedDatetime.toISOString())
: this.$emit('input', this.selectedDatetime)
},
clearHandler() {
this.resetPicker()
this.date = DEFAULT_DATE
this.time = DEFAULT_TIME
this.$emit('input', null)
},
cancelHandler() {
this.resetPicker()
this.init()
},
outsiteHandler() {
if (!this.persistent) {
this.cancelHandler()
}
},
resetPicker() {
this.display = false
this.activeTab = 0
Expand Down