How can i pull dynamic data using v-model and moment js - vue.js

I can already pull the data from api with v-model, but this is how i see the date 2022-04-23T13:39:00+03:00 but I want it to come this way 2022-04-23 13:39
Here is my html code
<Field
class="form-control"
type="text"
v-model="date"
name="date"
:placeholder="$t('form.label.date')"
/>
Here is my ts code
data() {
date:"",
}
setup() {
const dateFormat = (date) => {
return moment(date).format("YYYY-MM-DD HH:mm");
};
}

If you are only rendering the value and don't need to setup two-way binding or reactivity, you can just resolve the formatting before passing the formatted value to the template.
You can also pass a formatter function to the template that will render the formatting to you liking.
While there are several options for formatting dates. To avoid adding additional dependencies, I'm using Intl.DateTimeFormat in the example. It's a little hacky, since the format is not in any international standard (or it is, and just don't know which one). I've also used date-fns with success, but as mentioned in the comments, you should not be using moment. Moment is built in a way that doesn't allow tree-shaking unused parts during packaging, so leads to bloat.
const formatter = (dateStr) => {
const date = new Date(dateStr)
if (isNaN(date)) return "-- invalid date --";
// fr-CA for YYYY-MM-DD + en-GB for 24hour hh:mm:ss
return new Intl.DateTimeFormat('fr-CA', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
timeZone: 'UTC'
}).format(date) + " " + new Intl.DateTimeFormat('en-GB', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZone: 'UTC'
}).format(date)
}
Vue.createApp({
setup() {
const date = Vue.ref("2022-04-23T13:39:00+03:00");
// using ref
const dateFormatted = formatter(date.value);
return {
date, // date string ref, to allow reactivity
dateFormatted, // pass non-reactive value to display
formatter // pass formatter function if reactive changes are needed
}
}
}).mount("#app");
input {
width: 400px;
padding: 6px;
margin-top: 2px;
}
<script src="https://unpkg.com/vue#3.2.31/dist/vue.global.prod.js"></script>
<div id="app">
<p>Date (v-model)<br/><input v-model="date" /></p>
<p>Formatted with Intl (read-only)<br/> <input :value="dateFormatted" disabled/></p>
<p>Reactive formatted with Intl (read-only)<br/> <input :value="formatter(date)" disabled /></p>
</div>

Related

Fill value of input with the time selected on Clockpicker in Angular 14

I'm using clockpicker to make the user select the time he wants, however, I'm trying since a couple of days to figure out how to retrieve the value of time chosen and assign it to the corresponding input value but in vain.
So here is the html code. Down there I'm using also ngModel to send the value to .ts file.
<div>
<mat-form-field appearance="outline">
<mat-label>Select the start time</mat-label>
<input
appClockPicker
#clockpicker="clockpicker"
matInput
placeholder="..."
type="text"
[(ngModel)]="selectedHours[0]"
/>
</mat-form-field>
</div>
Then this is the directive to display the clockpicker, but I'm not really understanding the way it workes since I'm beginner, and I was copying it from somewhere in internet. So I think the error is from there.
import {
AfterViewInit,
Directive,
ElementRef,
NgZone,
} from "#angular/core";
declare var $: any;
declare var jQuery: any;
#Directive({
selector: "[appClockPicker]",
exportAs: "clockpicker",
})
export class ClockPickerDirective implements AfterViewInit {
myDate: any;
constructor(private el: ElementRef, private ngZone: NgZone) {}
ngAfterViewInit(): void {
this.ngZone.runOutsideAngular(() => {
$(this.el.nativeElement).clockpicker({
placement: '',
align: "left",
donetext: "Valider",
onselect: (data:any) => {
console.log(`data: ${data}`);
this.ngZone.run((date) => {
this.setTime(date);
console.log(`date: ${date}`);
});
},
})});
;}
setTime(date) {
this.myDate = date;
}
}
Finally this how it looks : the selected time appear correctly in the input box though
enter image description here

disable future dates in vue3 using vue-2 datepicker?

How can I disable future dates while using date range?
<date-picker
v-model="params.range"
type="date"
value-type="format"
format="YYYY-MM-DD"
range
placeholder="Filter by date range"
/>
You can use the disabled-date prop to provide a function telling if a date should be disabled or not.
From the vue2-datepicker documentation demo (source code)
<template>
<div>
<p>Not before than today and not after than a week</p>
<date-picker
v-model="value1"
:default-value="new Date()"
:disabled-date="disabledAfterToday"
></date-picker>
</div>
</template>
<script>
export default {
data() {
return {
value1: new Date(),
};
},
methods: {
disabledAfterToday(date) {
const today = new Date();
today.setHours(0, 0, 0, 0);
return date > today
},
},
};
</script>

How do I set a default value for v-model using computed property

I have two input fields for dates: to and from.
I want the user to be able to select dates that I will send a request to the backend. That is why I am using a computer property - in the setter I will validate the dates to make sure from is less than to and to is not less than from.
How do I set default values for those inputs?
I am using computed properties so I can set default values for both inputs. One value is set to now, the other is 1 week ago.
<template>
<div class="logs-listing-table">
<div class="mb-1 filter-actions-wrapper">
<input type="date" v-model="this.fromDate">
<input type="date" placeholder="this.toDate">
</div>
</div>
</template>
<script>
export default {
name: 'BnbReport',
data () {
return {
fromDate: this.fromDateDefault(),
toDate: this.toDateDefault()
}
},
computed: {
fromDateDefault () {
var previousPeriod = new Date()
previousPeriod.SetDate(previousPeriod.getDate() - 7)
previousPeriod.toISOString().substr(0, 10)
this.fromDate = previousPeriod
return this.fromDate
},
toDateDefault () {
var today = new Date()
today.toISOString().substr(0, 10)
this.toDate = today
return this.toDate
}
}
}
</script>
However, eslint throws me an error:
Unexpected side effect in "fromDateDefault" computed property
Unexpected side effect in "toDateDefault" computed property
You can add get and set functions into your computed property.
HTML:
<input type="date" v-model="fromDateDefault">
JS:
computed: {
fromDateDefault: {
get() {
//your validation
return this.fromDate;
},
set(val) {
this.fromDate = val;
},
},
}
You can read more about the setters and getters in the official doc:
https://v3.vuejs.org/guide/computed.html#computed-properties

How can I validate date after / date before using VeeValidate v3 and vuejs-datepicker?

How can I validate, using VeeValidate v3 and VueJs-DatePicker, if a date is before or after a certain date?
I am using:
https://www.npmjs.com/package/vuejs-datepicker (latest)
and
https://baianat.github.io/vee-validate/ (Version 3, not 2)
VeeValidate removed its date validation capabilities, stating that the rules were fragile, didn't work great, etc.
So I am assuming I need to create custom rules but I don't really know where to start with this and could use help.
I am using the VueJS-DatePicker package as a datepicker and I am using a custom format via the "format" attribute.
My datepicker code
<datepicker
v-model="inputVal"
:class="{ 'has-errors': !!errors[0] }"
:placeholder="placeholder"
calendar-button
calendar-button-icon="fal fa-calendar-alt"
bootstrapStyling
:typeable="true"
:disabled-dates="disabledDates"
:format="customFormatter"
></datepicker>
Using Moment to format the date
customFormatter(date) {
return moment(date).format('MM/DD/YYYY');
},
expanding on #Barabas answer to specifically include a) before a given date b) the momentJS library c) the strict date format 'MM/DD/YYYY'
import { extend } from "vee-validate";
import * as moment from 'moment';
const dateFormat = 'MM/DD/YYYY';
extend("before", {
params: ["limit", "included"],
validate: (value, { limit, included }) => {
limit = moment(limit, dateFormat);
value = moment(value, dateFormat);
return included
? value.isSameOrBefore(limit)
: value.isBefore(limit);
},
message: (fieldName, placeholders) => {
let limit = moment(placeholders.limit).format(dateFormat);
return `The ${fieldName} field must come before ${limit}`;
}});
}
and without moment (with the caveat that different localization setting in the users browser could result in funkiness when using strings for either a Vue data property or the limit parameter - I would strongly suggest using 'YYYY-MM-DD' format if using strings - this does not have to be what is shown to the user of course)
extend("before", {
params: ["limit", "included", "displayTime"],
validate: (value, { limit, included }) => {
value = isNaN(value)
? Date.parse(value)
: +value;
limit = isNaN(limit)
? Date.parse(limit)
: +limit;
return included
? value <= limit
: value < limit;
},
message: (fieldName, placeholders) => {
let limit = placeholders.limit instanceof Date
? placeholders.limit
: new Date(placeholders.limit);
limit = placeholders.displayTime
? limit.toLocaleString()
: limit.toLocaleDateString();
return `The ${fieldName} field must come before ${limit}`
}});
}
Create your custom rule using extend
For example, this is my own custom rule to check if it is enough items in collection:
value below is a value from input (unfortunately, vee-validate works only with input)
min is a value after semicolon in rules prop of ValidationProvider
extend('minAmountItems', {
validate: (value, { min }) => {
return value >= min;
},
params: ['min'],
message: '{_field_} should contains at least {min} items'
});
Wrap you datepicker by ValidationProvider
For example, I wrapped my own component by ValidationProvider:
HTML
<ValidationProvider
ref="editableListProvider"
tag="div"
rules="minAmountItems:2"
v-slot="{errors,invalid}"
name="Collection"
>
<!-- LINE BELOW IS VERY IMPORTANT. -->
<!-- THIS INPUT VALUE GOES TO VALIDATE FUNCTION OR CUSTOM RULE -->
<input type="text" :value="items.length" disabled v-show="false" />
<div class="column add-item-column">
<button #click="addItem">Add item</button>
</div>
<div class="column alert alert-danger" v-show="invalid">{{ errors[0] }}</div>
<div class="column" v-for="(item, i) in items" :key="i">
<div class="row as-row row-no-padding">
<slot name="data" :data="{item, index: i}"></slot>
<div class="column column-clear">
<button class="button-outline button-icon" #click="removeItem(i)">
<i class="la la-close"></i>
</button>
</div>
</div>
</div>
</ValidationProvider>
JS
// another part of my component
methods: {
addItem() {
this.$emit('editableList:itemAdded');
this.$nextTick(async () => {
// LINE BELOW IS IMPORTANT, BECAUSE AUTOMATIC VALIDATE WORKS
// ONLY ONCHANGE EVENT OF INPUT
this.$refs.editableListProvider.validate();
});
},
removeItem(index) {
this.$emit('editableList:itemRemoved', { index });
this.$nextTick(async () => {
// LINE BELOW IS IMPORTANT, BECAUSE AUTOMATIC VALIDATE WORKS
// ONLY ONCHANGE EVENT OF INPUT
this.$refs.editableListProvider.validate();
});
}
// other my methods
}

Vue JS date of birth picker

I'm setting up a date of birth field.
How can I set the "Year" as my first popup window? instead of calendar view popup.
The view package I'm using is "vue2-datepicker"
I would like to choose the "YEAR" first and then "Month" and then "Date"
This is what I want to show up first when I click the calendar icon.
At the moment, when I click the calendar icon it show the default calendar.
Here's the code I have at the moment. It's working fine with the default calendar but I just want to default to the year selection first and then Month and then date.
<template>
<div class="styled-form__field">
<label class="styled-form__label">{{ label }}</label>
<span
:class="['styled-form__error', {'is-visible': error}]"
>{{ error }}</span>
<date-picker
:value="value"
lang="en"
:format="'DD MMMM YYYY'"
:placeholder="' '"
:width="'auto'"
:input-class="datePickerClass"
:not-before="datePicker.start"
:not-after="datePicker.finish"
#input="changeHandler"
></date-picker>
</div>
</template>
<script>
import moment from 'moment';
import DatePicker from '../common/DatePicker.vue';
export default {
components: {
DatePicker
},
props: {
value: {
required: true
},
label: String,
error: String
},
data() {
return {
datePicker: {
start: moment().subtract(115, 'years').toDate(),
finish: moment().subtract(1, 'days').toDate()
}
};
},
computed: {
datePickerClass() {
return this.error ? 'styled-form__date-picker is-invalid' : 'styled-form__date-picker';
}
},
methods: {
changeHandler(newValue) {
let parsedValue = '';
if (newValue !== '') {
parsedValue = moment(newValue).format('YYYY-MM-DD');
}
this.$emit('input', parsedValue);
}
}
};
</script>
The standard browser datepicker doesn't let you alter its behaviour like that. You might find another datepicker component that suits you better, but I suspect you will have to write your own, combining separate inputs for year, month and date. The effort will only be worth it if you're super-picky about the result. For most situations, you will be better off with a ready-made component.