Reputation: 435
I have DatePicker component, and I want implements choice multiple dates on one Calendar component(DatePicker
). Any ideas?
My idea:
Create an array with 2 values: startDate
and endDate
and int property "step" with an initial value are 0.
If I click on first cell date, step equal to 1, initial startDate
and when step equals 1 I can click on second cell and initial endDate
And how store intermediate values around startDate
and endDate
?
Upvotes: 1
Views: 385
Reputation: 34914
Going forward with your example and idea to make
setDateRange(dt) {
let dateFor = this.step ? 'endDate' : 'startDate';
this.rangeData[dateFor] = dt;
},
selectStartEnd(){
this.step = !this.step;
},
so here is complete demo
var V = new Vue({
el: "#app",
filters: {
monthName(month) {
if(month === 0) {
return 'Jan'
}
else if(month === 1) {
return 'Feb'
}
else if(month === 2) {
return 'Маr'
}
else if(month === 3) {
return 'Apr'
}
else if(month === 4) {
return 'May'
}
else if(month === 5) {
return 'Jun'
}
else if(month === 6) {
return 'Jul'
}
else if(month === 7) {
return 'Aug'
}
else if(month === 8) {
return 'Sep'
}
else if(month === 9) {
return 'Oct'
}
else if(month === 10) {
return 'Nov'
}
else if(month === 11) {
return 'Dec'
}
}
},
data() {
const startDate = new Date()
return {
isShow: false,
selectedDate: null,
pageTimestamp: startDate.setDate(1),
step: 0,
message: '',
rangeData: {
startDate: null,
endDate: null
},
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
daysOfWeek: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
}
},
computed: {
days() {
const d = this.pageDate
let days = []
let dObj = new Date(d.getFullYear(), d.getMonth(), 1)
let daysInMonth = this.isDaysInMonth(dObj.getFullYear(), dObj.getMonth())
for(let i = 0; i < daysInMonth; i++) {
days.push({
date: dObj.getDate(),
fullDate: dObj.toLocaleDateString(),
// Неделя начинается с 0. 0 - Воскресенье, 1 - понедельник,... 6 - суббота
isWeekend: dObj.getDay() === 0 || dObj.getDay() === 6,
isSaturday: dObj.getDay() === 6,
isSunday: dObj.getDay() === 0
})
dObj.setDate(dObj.getDate() + 1)
}
return days
},
getMonth() {
return this.pageDate.getMonth()
},
pageDate() {
return new Date(this.pageTimestamp)
},
formattedValue() {
let str = [];
if(this.rangeData.startDate !== null){
str.push(this.rangeData.startDate.fullDate);
}
if(this.rangeData.endDate !== null){
str.push(this.rangeData.endDate.fullDate);
}
return str.join(' - ');
},
},
methods: {
setDateRange(dt) {
let dateFor = this.step ? 'endDate' : 'startDate';
this.rangeData[dateFor] = dt;
},
selectStartEnd(){
this.step = !this.step;
},
validateDates(){
let startMilliSeconds = Date.parse(this.rangeData.startDate.fullDate);
let endMilliSeconds = Date.parse(this.rangeData.endDate.fullDate);
if(endMilliSeconds < startMilliSeconds){
this.message = "Start must be less than End date";
}else{
this.message = "Dates are valid";
this.showCalendar();
}
},
updateRangeDate(rangeDate) {
this.rangeDate = rangeDate
},
showCalendar () {
this.isShow = !this.isShow;
},
startDate(index) {
this.$emit('start-date', this.days[index].fullDate)
},
endDate(index) {
this.$emit('end-date', this.days[index].fullDate)
},
formatDate (date, format) {
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
let str = format.replace(/yyyy/, year).replace(/d/, day)
return str
},
isDaysInMonth (year, month) {
// В 8, 3, 5, 10 месяце - 30 дней
return /8|3|5|10/.test(month) ? 30 : month === 1 ? (!(year % 4) && year % 100) || !(year % 400) ? 29 : 28 : 31
},
changeMonth (incrementBy) {
let date = this.pageDate;
date.setMonth(date.getMonth() + incrementBy)
this.setPageDate(date)
},
previousMonth() {
this.changeMonth(-1)
},
nextMonth () {
this.changeMonth(+1)
},
setPageDate (date) {
this.pageTimestamp = (new Date(date)).setDate(1)
},
}
});
.calendar {
color: #fff;
}
.calendar__month {
color: #fff;
}
.calendar__prev,
.calendar__next {
background-color: #bd3ba6;
border-radius: 11px;
width: 20px;
height: 20px;
}
.calendar__input {
display: none;
}
.calendar__list {
position: relative;
border-bottom: 1px solid #6d7ab9;
min-width: 200px;
}
.calendar__list p {
color: #5a64aa;
}
.calendar__list:after {
content: '';
position: absolute;
right: 0;
top: 2px;
border: 6px solid transparent;
border-top: 8px solid #6d7ab9;
}
.calendar__arrow-left {
padding: 5px;
border: #fff;
border-width: 0 10px 10px 0;
}
.calendar__box {
margin-top: 10px;
padding: 25px 30px 15px 30px;
box-shadow: 0 0 4px rgba(0,0,0,0.5);
background-color: #1c2247;
}
.calendar__day p {
color: rgba(255,255,255,0.46);
}
.calendar__days {
margin-top: 35px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.calendar__days-box {
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.calendar__cell {
padding: 5px;
}
.calendar__header {
display: flex;
justify-content: space-between;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div class="calendar">
<div
class="calendar__wrapper">
<input
:value="formattedValue"
placeholder="The calendar"
readonly
type="text"
class="calendar__input">
<div
class="calendar__list"
@click="showCalendar">
<p>The calendar</p>
</div>
<div v-show="formattedValue" class="calendar__box">
{{ formattedValue }}
</div>
<div v-show="message" class="calendar__box">{{message}}</div>
<div v-show="isShow">
<div class="calendar__box">
<header class="calendar__header">
<span
class="calendar__prev"
@click="previousMonth">
<span class="calendar__arrow-left"/>
</span>
<h3 class='calendar__month'>{{ getMonth | monthName(getMonth) + ' ' + pageDate.getFullYear() }}</h3>
<span
class="calendar__next"
@click="nextMonth">
</span>
</header>
<div class="calendar__days">
<div
class="calendar__day"
v-for="(weekDay, index) in daysOfWeek">
<p>{{ weekDay }}</p>
</div>
<div class="calendar__days-box">
<!-- add some method for ranges when click on cell -->
<p
v-for="(day, index) in days"
:key="index"
@click="setDateRange(day)"
class="calendar__cell calendar__cell_day">{{ day.date }}</p>
</div>
</div>
<button @click="selectStartEnd">{{step ? 'Select End Date':'Select Start Date'}}</button>
<button @click="validateDates">Ok</button>
</div>
</div>
</div>
</div>
</div>
Live demo on codesandbox
Now you can handle this.rangeData
or display anywhere.
Upvotes: 1