end date must be less than start date, Vuelidate and VueJs - javascript

I'm having problems doing a form validation. I have a start date and an end date. I need to confirm that the end date is greater than the start date.
I'm using vuejs and vuelidate.
I'm working with an Input.vue component, which has a standard input being reused in other forms. I also have a Form.vue component that has Input.vue inside. And this Form.vue component is called both in the modal of creating a new event and in the editing mode.
My problem is in the validation of when the event is edited. If you select an end date less than the start date, it doesn't allow saving the information, that's ok. However, when trying to correct it by selecting a date greater than the start date, and clicking on save again, it seems that it is no longer calling validation. With this, the error that the end date must be greater than the initial one does not disappear. I did several tests and noticed that validation is not called after the error occurs when editing. I do not know why.
component Input.vue:
<template>
<b-form-group :label="label" :label-for="labelFor">
<b-form-input
:id="labelFor"
v-model="value"
:type="type"
:placeholder="placeholder"
:class="{ 'is-invalid': this.isInvalid }"
required>
</b-form-input>
<slot></slot>
</b-form-group>
</template>
<script>
export default {
name: 'InputForm',
props: [ 'label', 'labelFor', 'vModel', 'type', 'placeholder', 'isInvalid' ],
computed: {
value: {
get() {
return this.vModel
},
set(value) {
this.newValue = value
return this.$emit('emitValue', this.newValue)
}
}
},
}
</script>
component Form.vue:
<template>
<b-form>
....
<InputForm
class="col-8 pl-0"
:label="'*Início'"
:labelFor="'event_start_at_date'"
:vModel="event.start_at_date"
:type="'date'"
#emitValue="($event) => event.start_at_date = $event"
/>
<InputForm
class="col-4 pr-0"
v-if="!event.all_day"
:labelFor="'event_start_at_time'"
:vModel="event.start_at_time"
:type="'text'"
#emitValue="($event) => event.start_at_time = $event"
/>
</b-col>
<b-col cols="12" lg="6" class="d-flex align-items-end">
<InputForm
class="col-8 pl-0"
:label="'*Fim'"
:labelFor="'event_end_at_date'"
:type="'date'"
:vModel="event.end_at_date"
#emitValue="($event) => event.end_at_date = $event"
:isInvalid="invalid.end_at_date.$error"
>
<b-form-invalid-feedback v-if="this.submitted" :state="invalid.end_at_date.$error == 0">Fim deve ser maior que início.</b-form-invalid-feedback>
</InputForm>
<InputForm
class="col-4 pr-0"
v-if="!event.all_day"
:labelFor="'event_end_at_time'"
:vModel="event.end_at_time"
:type="'text'"
:isInvalid="invalid.end_at_date.$error"
:class="{ 'error' : invalid.end_at_date.$error }"
#emitValue="($event) => event.end_at_time = $event"
/>
...
</b-form>
</template>
export default {
name: 'Form',
props: [ 'event', 'event_shared', 'error', 'submitted' ],
components: { Input },
computed: {
invalid() {
if(this.error.edit_event != undefined) {
return this.error.edit_event
} else if(this.error.event != undefined) {
return this.error.event
} else {
return false;
}
},
stateInvalid() {
if(this.error.edit_event != undefined) {
return this.error.edit_event
} else if(this.error.event != undefined) {
return this.error.event
} else {
return 0;
}
},
},
watch: {
event() {
let newEvent = this.event
this.$emit('emitObj', newEvent)
},
},
}
</script>
component ModalEditEvent.vue:
...
<VWarningErrorForm v-if="$v.$error" />
<FormEvent
:event="edit_event"
:event_shared="get_shared_users_id"
:error="this.$v"
:submitted="this.submitted"
#emitObj="($event) => edit_event = $event"
/>
...
<b-button
v-if="editEvent && !view_popover_save"
variant="primary" type="submit" #click="save()">Gravar</b-button>
...
<script>
import moment from 'moment';
import { required } from "vuelidate/lib/validators";
import isAfterDate from '#/functions/isAfterDate'
...
validations: {
edit_event: {
name: {
required
},
end_at_date: {
required: function(value) {
return isAfterDate(value, this.edit_event);
}
},
},
},
...
save() {
this.submitted = true;
this.$v.$touch();
if(!this.$v.$error) {
....
}
},
validation
import moment from 'moment';
function isAfterDate(value, vm) {
let hour = function(att) {
return `${att[0]}${att[1]}`;
}
let minute = function(att) {
return `${att[3]}${att[4]}`;
}
let start = moment(vm.start_at_date).set({hour: hour(vm.start_at_time), minute: minute(vm.start_at_time) })._d
let end = moment(vm.end_at_date).set({hour: hour(vm.end_at_time), minute: minute(vm.end_at_time) })._d
return end >= start;
}
export default isAfterDate;

Solved my issue with Vue.set. I realized that I was trying to detect the change of a property that I added later myself. So I had to use Vue.set when adding the property, so I could detect the change later, and then correctly validate the form. Thanks to whoever tried to help me!

Related

how to fix Error componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops

I use react js to create a staycation website, when I want to display the InputNumber and InputDate components I experience an error like the title above, in the componentDidUpdate section, I have tried tweaking the code but it hasn't worked, but when I omit the componentDidUpdate part, the inputdate and inputnumber components run.
this is the input component code Number I have tried the input component works well,:
import React from "react";
import propTypes from "prop-types";
import "./index.scss";
export default function Number(props) {
const {
value,
placeholder,
name,
min,
max,
prefix,
suffix,
isSuffixPlural,
} = props;
const onChange = (e) => {
let value = String(e.target.value);
if (+value <= max && +value >= min) {
props.onChange({
target: {
name: name,
value: +value,
},
});
}
};
const minus = () => {
value > min &&
onChange({
target: {
name: name,
value: +value - 1,
},
});
};
const plus = () => {
value < max &&
onChange({
target: {
name: name,
value: +value + 1,
},
});
};
return (
<div className={["input-number mb-3", props.outerClassName].join(" ")}>
<div className="input-group">
<div className="input-group-prepend">
<span className="input-group-text minus" onClick={minus}>
-
</span>
</div>
<input
min={min}
max={max}
name={name}
pattern="[0-9]*"
className="form-control"
placeholder={placeholder ? placeholder : "0"}
value={`${prefix}${value}${suffix}${
isSuffixPlural && value > 1 ? "s" : ""
}`}
onChange={onChange}
/>
<div className="input-group-append">
<span className="input-group-text plus" onClick={plus}>
+
</span>
</div>
</div>
</div>
);
}
Number.defaultProps = {
min: 1,
max: 1,
prefix: "",
suffix: "",
};
Number.propTypes = {
value: propTypes.oneOfType([propTypes.string, propTypes.number]),
onChange: propTypes.func,
placeholder: propTypes.string,
isSuffixPlural: propTypes.bool,
outerClassName: propTypes.string,
};
and this is my input date component code I have tried the input component works well, :
import React, { useState, useRef, useEffect } from "react";
import propTypes from "prop-types";
import { DateRange } from "react-date-range";
import "./index.scss";
import "react-date-range/dist/styles.css"; // main css file
import "react-date-range/dist/theme/default.css"; // theme css file
import formatDate from "utils/formatDate";
import iconCalendar from "assets/images/icon/icon-calendar.svg";
export default function Date(props) {
const { value, placeholder, name } = props;
const [isShowed, setIsShowed] = useState(false);
const datePickerChange = (value) => {
const target = {
target: {
value: value.selection,
name: name,
},
};
props.onChange(target);
};
useEffect(() => {
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
});
const refDate = useRef(null);
const handleClickOutside = (event) => {
if (refDate && !refDate.current.contains(event.target)) {
setIsShowed(false);
}
};
const check = (focus) => {
focus.indexOf(1) < 0 && setIsShowed(false);
};
const displayDate = `${value.startDate ? formatDate(value.startDate) : ""}${
value.endDate ? " - " + formatDate(value.endDate) : ""
}`;
return (
<div
ref={refDate}
className={["input-date mb-3", props.outerClassName].join(" ")}
>
<div className="input-group">
<div className="input-group-prepend bg-gray-900">
<span className="input-group-text">
<img src={iconCalendar} alt="icon calendar" />
</span>
</div>
<input
readOnly
type="text"
className="form-control"
value={displayDate}
placeholder={placeholder}
onClick={() => setIsShowed(!isShowed)}
/>
{isShowed && (
<div className="date-range-wrapper">
<DateRange
editableDateInputs={true}
onChange={datePickerChange}
moveRangeOnFirstSelection={false}
onRangeFocusChange={check}
ranges={[value]}
/>
</div>
)}
</div>
</div>
);
}
Date.propTypes = {
value: propTypes.object,
onChange: propTypes.func,
placeholder: propTypes.string,
outerClassName: propTypes.string,
};
I have tried the inpudate component to run well, as well as the input number, but if I combine these components I have an error did i miss something, and I tried to combine these components on the bookingform page but when I tried on the browser I experienced the above error.
My code is in the Booking Form:
import React, { Component } from "react";
import propTypes from "prop-types";
import Button from "elements/Button";
import { InputNumber, InputDate } from "elements/Form";
export default class BookingForm extends Component {
constructor(props) {
super(props);
this.state = {
data: {
duration: 1,
date: {
startDate: new Date(),
endDate: new Date(),
key: "selection",
},
},
};
}
updateData = (e) => {
this.setState({
...this.state,
data: {
...this.state.data,
[e.target.name]: e.target.value,
},
});
};
componentDidUpdate(prevProps, prevState) {
const { data } = this.state;
if (prevState.data.date !== data.date) {
const startDate = new Date(data.date.startDate);
const endDate = new Date(data.date.endDate);
const countDuration = new Date(endDate - startDate).getDate();
this.setState({
data: {
...this.state.data,
duration: countDuration,
},
});
}
if (prevState.data.duration !== data.duration) {
const startDate = new Date(data.date.startDate);
const endDate = new Date(
startDate.setDate(startDate.getDate() + +data.duration - 1)
);
this.setState({
...this.state,
data: {
...this.state.data,
date: {
...this.state.data.date,
endDate: endDate,
},
},
});
}
}
startBooking = () => {
const { data } = this.state;
this.props.startBooking({
_id: this.props.itemDetails._id,
duration: data.duration,
date: {
startDate: data.date.startDate,
endDate: data.date.endDate,
},
});
this.props.history.push("/checkout");
};
render() {
const { data } = this.state;
const { itemDetails } = this.props;
console.log(this.state);
return (
<div className="card bordered" style={{ padding: "60px 80px" }}>
<h4 className="mb-3">Start Booking</h4>
<h5 className="h2 text-teal mb-4">
${itemDetails.price}{" "}
<span className="text-gray-500 font-weight-light">
per {itemDetails.unit}
</span>
</h5>
<label htmlFor="duration">How long you will stay?</label>
<InputNumber
max={30}
suffix={" night"}
isSuffixPlural
onChange={this.updateData}
name="duration"
value={data.duration}
/>
<label htmlFor="date">Pick a date</label>
<InputDate onChange={this.updateData} name="date" value={data.date} />
<h6
className="text-gray-500 font-weight-light"
style={{ marginBottom: 40 }}
>
You will pay{" "}
<span className="text-gray-900">
${itemDetails.price * data.duration} USD
</span>{" "}
per{" "}
<span className="text-gray-900">
{data.duration} {itemDetails.unit}
</span>
</h6>
<Button
className="btn"
hasShadow
isPrimary
isBlock
onClick={this.startBooking}
>
Continue to Book
</Button>
</div>
);
}
}
BookingForm.propTypes = {
itemDetails: propTypes.object,
startBooking: propTypes.func,
};
I encountered this error and tried to fix it, but couldn't find a solution to the problem
I use react js to create a staycation website, when I want to display the InputNumber and InputDate components I experience an error like the title above, in the componentDidUpdate section, I have tried tweaking the code but it hasn't worked, but when I omit the componentDidUpdate part, the inputdate and inputnumber components run.
I encountered this error and tried to fix it, but couldn't find a solution to the problem
I use react js to create a staycation website, when I want to display the InputNumber and InputDate components I experience an error like the title above, in the componentDidUpdate section, I have tried tweaking the code but it hasn't worked, but when I omit the componentDidUpdate part, the inputdate and inputnumber components run.
I encountered this error and tried to fix it, but couldn't find a solution to the problem
I use react js to create a staycation website, when I want to display the InputNumber and InputDate components I experience an error like the title above, in the componentDidUpdate section, I have tried tweaking the code but it hasn't worked, but when I omit the componentDidUpdate part, the inputdate and inputnumber components run.

Disable Submit button if the form fields' values have not changed in Vue/Nuxt

My question is simple. I have a form where a user can edit the entry in a Nuxt/Vue app. Now I want to disable the submit button until the form field's values have not changed. I use Vuex store to get the entry.
// store/users.js
export const state = () => ({
currentCustomer: null,
})
export const actions = {
async fetchCustomer({ commit }, customerId) {
const customer = await this.$strapi.$customers.findOne(customerId)
commit('setCurrentCustomer', customer)
}
}
export const mutations = {
setCurrentCustomer(state, customer) {
state.currentCustomer = customer
},
}
Here is my Vue/Nuxt Template:
<template>
<section class="d-flex flex-column mb-5">
<b-form v-else class="border rounded bg-white p-4 shadow-sm" #submit.stop.prevent="saveUser">
<b-form-group class="capital" label-for="name">
<template v-slot:label> Name <span class="text-danger">*</span> </template>
<b-form-input id="name" v-model.trim="form.name" type="text" autofocus required></b-form-input>
</b-form-group>
<b-form-group class="capital" label-for="email">
<template v-slot:label> Email <span class="text-danger">*</span> </template>
<b-form-input id="email" v-model.trim="form.email" type="email" required></b-form-input>
</b-form-group>
<p>Changed: {{ changed }}</p>
<code>Actual: {{ actual }}</code>
<code>Form: {{ form }}</code>
<b-row>
<b-col>
<button type="submit" :disabled="!changed">Save</button>
</b-col>
</b-row>
</b-form>
</section>
</template>
<script>
export default {
data() {
return {
changed: false,
}
},
computed: {
form() {
return this.$store.state.users.currentCustomer
},
actual() {
return this.$store.state.users.currentCustomer
},
},
watch: {
form(newValue) {
this.changed = newValue !== this.actual
},
},
created() {
this.$store.dispatch('users/fetchCustomer', this.$route.params.id)
},
}
</script>
The above code is not working. I know that something needs to be watched but I can't get my head around this issue. I would appreciate any help.
for object value, add a deep in watch, also, you need lodash.isEqual() to compare if two objects are equal
import _ from 'lodash';
...
watch: {
form: {
handler(value){
if(value) {
this.changed = !_.isEqual(value, this.actual);
}
},
deep: true,
}
},
...
Try to use #change="onChangeFn" or v-on:change="onChangeFn" on
methods: {
onChangeFn () {
this.changed = true
}
}

Inputs and models not correctly filling with data

So In my application I am trying to load a quiz and its data from an API, which works perfectly fine. Then I try to reperesent this data in the UI, which works partially fine. There are some very weird things going on which seem like magic to me.
The first example is when I am trying to load the quiz and its questions in my main page: QuizEditor.vue. This page and its loading look like this:
export default {
components: {QuestionCard, EditorGeneralBar, EditorQuestionBar},
name: 'QuizEditor',
data() {
return {
count: 1,
editorTitle: "General",
newQuiz: true,
newQuestion: true,
currentQuestion: null,
quiz: {
tn: "",
title: "My quiz",
description: "A quiz",
timeLimit: 60,
theme: 1
},
options: {
multipleDropzonesItemsDraggingEnabled: false,
dropzoneSelector: ".q-list",
draggableSelector: ".question-card"
},
currentPosition: 1,
questions: []
}
},
mounted() {
var QE = this;
QuizTemplateRepository.getTemplate("k472ahe3r", this.$store.state.X_CSRFToken).then(function (res) {
QE.quiz = {
tn: "k472ahe3r",
title: res.data.template.label,
description: res.data.template.description,
};
QuizTemplateRepository.getTemplateContent(QE.quiz.tn, QE.$store.state.X_CSRFToken).then(function (res) {
var questions = JSON.parse(res.data.content.content).questions;
QE.quiz.theme = JSON.parse(res.data.content.content).properties.theme;
QE.quiz.timeLimit = JSON.parse(res.data.content.content).properties.timeLimit;
QE.quiz.questions = questions;
questions.forEach(question => {
QuestionRepository.getQuestion(question, QE.$store.state.X_CSRFToken).then(function (resQuest) {
var vogh = resQuest.data.var[0].vogh;
AnswerRepository.getAnswer(vogh, QE.$store.state.X_CSRFToken).then(function(resAnswer) {
var quest = {
name: resQuest.data.var[0].name,
hash: resQuest.data.var[0].vh,
vogh: resQuest.data.var[0].vogh,
label: resQuest.data.var[0].label,
position: resQuest.data.var[0].position,
description: "",
answers: []
}
resAnswer.data.varoptiongroup.forEach(answer => {
answer.place = QE.getPositionString(answer.position);
if(answer.value > 0)
answer.isCorrect = true;
else
answer.isCorrect = false;
quest.answers.push(answer);
});
QE.questions.push(quest);
QE.currentPosition++;
});
})
});
});
});
},
...
}
The data above from the API calls load just fine and I have quadrupple checked this by putting console logs on practically every line. The first issue comes from EditorGeneralBar, this will have the quiz object which it will receive like this:
<EditorGeneralBar :quiz="quiz" v-if="editorTitle === 'General'" #submitQuiz="submitQuiz" #themeSelected="selectTheme"></EditorGeneralBar>
This component looks like this:
<template>
<div class="bar-content">
<q-form
#submit="submit"
class="q-gutter-md"
>
<q-input
filled
v-model="quiz.title"
label="Title"
lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-input
filled
type="text"
v-model="quiz.description"
label="Description"
lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-input
filled
type="number"
v-model="quiz.timeLimit"
label="Time limit"
lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-file filled bottom-slots v-model="quiz.thumbnail" label="Thumbnail">
<template v-slot:before>
<q-icon name="folder_open" />
</template>
<template v-slot:hint>
A thumbnail for the quiz.
</template>
<template v-slot:append>
<q-btn round dense flat icon="add" #click.stop />
</template>
</q-file>
<p>Themes</p>
<div class="theme-list">
<div class="theme-1 theme-preview" v-on:click="selectTheme(1)"></div>
<div class="theme-2 theme-preview" v-on:click="selectTheme(2)"></div>
<div class="theme-3 theme-preview" v-on:click="selectTheme(3)"></div>
<div class="theme-4 theme-preview" v-on:click="selectTheme(4)"></div>
<div class="theme-5 theme-preview" v-on:click="selectTheme(5)"></div>
</div>
<div>
<q-btn label="Save" type="submit" color="primary"/>
</div>
</q-form>
</div>
</template>
<script>
export default {
name: 'EditorGeneralBar',
props: ["quiz"],
components: [
'QBtn'
],
methods: {
submit:function() {
this.$emit("submitQuiz");
},
selectTheme:function(theme) {
this.$emit("themeSelected", theme);
}
}
}
</script>
Everything in this component gets filled just fine, but not the timeLimit, this only gets loaded when I edit something like the description or title.
This also happens on the QuizEditor.vue where I try to load a class based on the template's theme.
This will be done like below(thase are placed in methods):
/**
* Select a theme by its number.
* #param {Number} theme
*/
selectTheme: function(theme) {
this.quiz.theme = theme;
console.log(this.quiz.theme);
},
/**
* Get the selected theme of the quiz.
*/
getTheme: function() {
return "theme-"+this.quiz.theme;
},
and the html looks like this:
<div class="question-listing" v-bind:class="getTheme()">
...
</div>
Summary
So to summarize it all, each component only loads data partially. The full data is there when I load it from the API and the data which is not being shown in the UI comes when I manipulate something in that component.
Can somebody tell me what is going wrong and how I can load ALL of the data correctly into my UI.

Dynamic content with v-show in Bootstrap vue popover

I am struggling to show a dynamic content inside my popover built with Bootstrap Vue component.
I want to show a form first, and when that form is submitted successfully I want to show a confirmation text instead.
I tried to manage that with v-show directive within the popover content with no success. Everything is displayed of course outside the div with the v-show directive.
The result is that it just shows an empty popover (except the close link) inside the popover.
Here is my component :
<template>
<div class="email-content">
<div class="email-content__buttons">
<b-button variant="blue" class="fv-round" id="testEmailSend" :disabled="isPopoverDisplayed" #click="isPopoverEmailFormDisplayed = true">{{locales.testButton}}</b-button>
<b-popover target="testEmailSend"
:show="isPopoverDisplayed"
placement="auto"
#show="isPopoverEmailFormDisplayed = true"
#shown="setFocusOnPopoverForm">
<template>
<b-btn #click="isPopoverEmailFormDisplayed = false" class="close">
<span class="d-inline-block">×</span>
</b-btn>
</template>
<div v-show="isPopoverConfirmationDisplayed">
<b-form-group :label="`${locales.sendTo} :`" label-for="popoverEmailForm" class="mb-1" :invalid-feedback="locales.emailMandatory">
<b-input-group>
<b-form-input ref="emailTestReceiver" id="popoverEmailForm" :validationState="$v.emailTestReceiver" size="sm" v-model="emailTestReceiver"></b-form-input>
<b-input-group-append>
<b-btn #click="sendEmailTest" size="sm" :disabled="$v.$invalid" variant="primary">Ok</b-btn>
</b-input-group-append>
</b-input-group>
</b-form-group>
</div>
</b-popover>
<div v-show="isPopoverConfirmationDisplayed" placement="auto">
{{locales.emailSentConfirmation}}
</div>
<b-button variant="primary" class="fv-round" #click="saveTemplates">{{locales.saveButton}}</b-button>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { required, email } from 'vuelidate/lib/validators';
import feedbackHandler from '#/components/_shared/Alerts/ErrorHandler';
import SellerEmailContentConfig from '#/components/SellerDashboard/SellerEmail/SellerEmailContent/SellerEmailContentConfig';
import locales from './sellerEmailContent.locales.json';
export default {
name: 'SellerEmailContent',
data() {
return {
locales,
emailTestReceiver: '',
isPopoverEmailFormDisplayed: false,
isPopoverConfirmationDisplayed: false
}
},
validations: {
emailTestReceiver: {
required,
email
}
},
computed: {
isPopoverDisplayed() {
return this.isPopoverEmailFormDisplayed || this.isPopoverConfirmationDisplayed;
}
},
methods: {
...mapActions({
sendEmail: 'sendAuthCustomEmail'
}),
async sendEmailTest() {
const { error: errorSending } = await this.sendEmail({ type: 'Seller', email: this.emailTestReceiver });
if (!errorSending) {
this.isPopoverEmailFormDisplayed = false;
this.isPopoverConfirmationDisplayed = true;
setTimeout(() => { this.isPopoverConfirmationDisplayed = false }, 3000);
} else feedbackHandler.showError(errorSending);
},
setFocusOnPopoverForm() {
this.$refs.emailTestReceiver.focus();
}
},
}
</script>
My last was as you can see above using a computed property which combines both situation (form or confirmation to be displayed).
Any idea ? I must have missed something :)

How to pass property value between to instances of a component

I have to datepicker components, from date and to date.
i want to update the to date with the from date if the to date is empty.
I've looked at doing emit on the value but feel this is not right and i'm not sure how to do it
<datepicker
input-label="From"
input-id="start-date"
input-name="start_date"
input-value="<%= group_discount.start_date %>"
#change-date="changeDate"
>
</datepicker>
<datepicker
input-label="To"
input-id="end-date"
input-name="end_date"
input-value="<%= group_discount.end_date %>">
</datepicker>
import Vue from "vue"
import Datepicker from "../components/DatePicker"
Vue.use(Datepicker)
const initGroupDiscount = () => {
new Vue({
el: "#js-group-discounts",
components: {
Datepicker,
},
methods: {
changeDate(value) {
console.log("value")
console.log(value)
},
},
})
}
document.addEventListener("DOMContentLoaded", () => {
initGroupDiscount()
})
<template>
<div >
<label :for="this.inputId">{{ this.inputLabel }}</label>
<input type="text"
class="form-control form-control-info"
placeholder="dd/mm/yyyy"
:name="this.inputName"
:id="this.inputId"
pattern="\d{1,2}/\d{1,2}/\d{4}"
required
v-model="isInput"
v-on:keyup="updateCalendar($event)"
ref="dateinput"
#blur="blur"
#focus="focus">
<datepicker format="dd/MM/yyyy"
input-class="form-control"
placeholder="dd/mm/yyyy"
v-model="isPicker"
:inline="true"
v-show="isOpen"
#mouseover.native="mouseOver"
#mouseleave.native="mouseLeave"
#selected="updateInput"></datepicker>
</div>
</template>
<script>
import Vue from "vue"
import Datepicker from "vuejs-datepicker"
Vue.use(Datepicker)
export default {
name: "neptune-datepicker",
props: {
inputLabel: {
type: String,
},
inputId: {
type: String,
},
inputValue: {
type: String,
},
inputName: {
type: String,
},
},
data(){
let value = ""
if (this.inputValue) {
const dateParts = this.inputValue.split("-")
value =`${dateParts[2]}/${dateParts[1]}/${dateParts[0]}`
}
return {
isInput: value,
isPicker: this.inputValue,
isOpen: false,
}
},
components: {
Datepicker
},
methods: {
updateInput(date) {
this.isInput = date.toLocaleDateString("en-GB")
this.$emit('changeDate', this.isInput);
},
updateCalendar(event) {
const dateString = event.srcElement.value
if (dateString.length === 10) {
const dateParts = dateString.split("/")
const dateObject = new Date(
dateParts[2],
dateParts[1],
dateParts[0],
)
if ((dateObject !== "Invalid Date") && !Number.isNaN(dateObject)) {
this.isPicker = dateObject
}
}
},
blur() {
this.isOpen = false
},
focus() {
this.$refs.dateinput.focus()
this.isOpen = true
},
mouseOver() {
this.$refs.dateinput.focus()
this.isOpen = true
},
mouseLeave() {
this.$refs.dateinput.focus()
this.isOpen = true
},
},
}
</script>
it emits the correct value to the console but i don't know how i would pass this to only that particular instance of the component, the "To" date
The parent component should pass a prop to both data sub-components:
<datepicker
:myValue="myValue"
input-label="From"
input-id="start-date"
input-name="start_date"
input-value="<%= group_discount.start_date %>"
#change-date="changeDate"
>
</datepicker>
<datepicker
:myValue="myValue"
input-label="To"
input-id="end-date"
input-name="end_date"
input-value="<%= group_discount.end_date %>">
</datepicker>
Then you can use that prop in a computed or method to validate if it contains a value or not and override the to or from value.
Edit: You can also use your emit strategy but you still need to pass a prop to one of the components so it can read the data. If you've never used props before read about them here: https://v2.vuejs.org/v2/guide/components-props.html

Categories