Issue
I am using flatpickr inside a project of mine. My scenario is that I have range date picker that uses flatpickr. After I select a range of dates, I have another date picker where all the selected dates get selected and turn green. Now, whenever I want to deselect a date from the selected dates, the date should turn red. If I select the deselected one, it should turn green again.
Here is the html code for the date pickers:
<div class="column-2 w-100 w-100 d-flex justify-content-between">
<p class="w-25 fs-6 fw-bold">Operational calendar</p>
<div class="w-75 d-flex gap-3">
<input type="text" name="" class="form-control bg-light" id="dateRangePicker" placeholder="Select date" />
{{-- <input type="date" class="form-control" /> --}}
</div>
</div>
<div class="column-2 w-100 w-100 d-flex justify-content-between">
<p class="w-25 fs-6 fw-bold">Opening and closing dates</p>
<div class="w-75 d-flex gap-3">
<input type="hidden" name="" />
<div id="dateRangePicker2" class="w-100"></div>
{{-- <input type="date" class="form-control" /> --}}
</div>
</div>
Here is the JavaScript code:
document.addEventListener("DOMContentLoaded", function () {
var dateRangePicker = document.getElementById("dateRangePicker");
var dateRangePicker2 = document.getElementById("dateRangePicker2");
var picker = flatpickr(dateRangePicker, {
mode: "range",
dateFormat: "d-m-Y",
onChange: function (selectedDates) {
updateMultiDatePicker(selectedDates);
},
});
var picker2 = flatpickr(dateRangePicker2, {
mode: "multiple",
dateFormat: "Y-m-d",
open: true,
inline: true,
allowInput: true,
onChange: function (selectedDates) {
updateDeselectedDates(selectedDates);
},
});
function updateMultiDatePicker(selectedDates) {
const allDates = document.querySelectorAll("#dateRangePicker2 .flatpickr-day");
allDates.forEach(function (el) {
el.classList.add("blabla");
});
// console.log(allDates)
if (selectedDates.length === 2) {
var startDate = selectedDates[0];
var endDate = selectedDates[1];
var datesToUpdate = [];
var currentDate = new Date(startDate);
while (currentDate <= endDate) {
datesToUpdate.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
picker2.setDate(datesToUpdate);
}
}
function updateDeselectedDates(selectedDates) {
const allSelectedDates = document.querySelectorAll(".flatpickr-day.selected");
// allSelectedDates.addClass
allSelectedDates.forEach(function (dateElement) {
dateElement.classList.add("blabla");
if (!dateElement.classList.contains("blabla")) {
dateElement.addEventListener("click", function () {
dateElement.classList.add("deselected");
});
}
const dateString = dateElement.getAttribute("aria-label");
const isSelected = selectedDates.includes(dateString);
// if (isSelected) {
// if (!dateElement.classList.contains('selected')) {
// dateElement.classList.add('deselected');
// } else {
// dateElement.classList.remove('deselected');
// }
// }
});
}
});
So as you can see for the green color dates, when they are deselected, the should turn red. This is what I want and this far I've got.
Solution
It seems like flatpickr doesn't provide an API to add custom classes to the date elements within the calendar, but we can select and style the deselected dates using their aria-label
values.
- Create a constructed stylesheet. This is where we will hold are CSS rules for the red deselected dates:
const disableStyles = new CSSStyleSheet(); document.adoptedStyleSheets.push(disableStyles);
- Get the list of
aria-labels
on the dates we are interested inupdateMultiDatePicker()
:function updateMultiDatePicker(selectedDates) { // … let ariaLabels = []; // … while (currentDate <= endDate) { // … ariaLabels = ariaLabels.concat( picker2.formatDate( new Date(currentDate), picker2.config.ariaDateFormat, ), ); // … }
- Convert this list of
aria-label
values to CSS selectors:const selectors = ariaLabels .map((label) => `[aria-label="${label}"]`) .join(",");
- Add the CSS rule to make these date cells in the calendar red:
disableStyles.replace( `#dateRangePicker2 + .flatpickr-calendar :is(${selectors}):not(.selected) { background-color: red }`, );
const disableStyles = new CSSStyleSheet();
document.adoptedStyleSheets.push(disableStyles);
document.addEventListener("DOMContentLoaded", function () {
var dateRangePicker = document.getElementById("dateRangePicker");
var dateRangePicker2 = document.getElementById("dateRangePicker2");
var picker = flatpickr(dateRangePicker, {
mode: "range",
dateFormat: "d-m-Y",
onChange: function (selectedDates) {
updateMultiDatePicker(selectedDates);
},
});
var picker2 = flatpickr(dateRangePicker2, {
mode: "multiple",
dateFormat: "Y-m-d",
open: true,
inline: true,
allowInput: true,
onChange: function (selectedDates) {
updateDeselectedDates(selectedDates);
},
});
function updateMultiDatePicker(selectedDates) {
const allDates = document.querySelectorAll(
"#dateRangePicker2 .flatpickr-day",
);
allDates.forEach(function (el) {
el.classList.add("blabla");
});
// console.log(allDates)
if (selectedDates.length === 2) {
var startDate = selectedDates[0];
var endDate = selectedDates[1];
var datesToUpdate = [];
let ariaLabels = [];
var currentDate = new Date(startDate);
while (currentDate <= endDate) {
datesToUpdate.push(new Date(currentDate));
ariaLabels = ariaLabels.concat(
picker2.formatDate(
new Date(currentDate),
picker2.config.ariaDateFormat,
),
);
currentDate.setDate(currentDate.getDate() + 1);
}
picker2.setDate(datesToUpdate);
const selectors = ariaLabels
.map((label) => `[aria-label="${label}"]`)
.join(",");
disableStyles.replace(
`#dateRangePicker2 + .flatpickr-calendar :is(${selectors}):not(.selected) { background-color: red }`,
);
}
}
function updateDeselectedDates(selectedDates) {
const allSelectedDates = document.querySelectorAll(
".flatpickr-day.selected",
);
// allSelectedDates.addClass
allSelectedDates.forEach(function (dateElement) {
dateElement.classList.add("blabla");
if (!dateElement.classList.contains("blabla")) {
dateElement.addEventListener("click", function () {
dateElement.classList.add("deselected");
});
}
const dateString = dateElement.getAttribute("aria-label");
const isSelected = selectedDates.includes(dateString);
// if (isSelected) {
// if (!dateElement.classList.contains('selected')) {
// dateElement.classList.add('deselected');
// } else {
// dateElement.classList.remove('deselected');
// }
// }
});
}
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" integrity="sha512-b2QcS5SsA8tZodcDtGRELiGv5SaKSk1vDHDaQRda0htPYWZ6046lr3kJ5bAAQdpV2mmA/4v0wQF9MyU6/pDIAg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.13/flatpickr.min.css" integrity="sha512-MQXduO8IQnJVq1qmySpN87QQkiR1bZHtorbJBD0tzy7/0U9+YIC93QWHeGTEoojMVHWWNkoCp8V6OzVSYrX0oQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.13/flatpickr.min.js" integrity="sha512-K/oyQtMXpxI4+K0W7H25UopjM8pzq0yrVdFdG21Fh5dBe91I40pDd9A4lzNlHPHBIP2cwZuoxaUSX0GJSObvGA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="column-2 w-100 w-100 d-flex justify-content-between">
<p class="w-25 fs-6 fw-bold">Operational calendar</p>
<div class="w-75 d-flex gap-3">
<input
type="text"
name=""
class="form-control bg-light"
id="dateRangePicker"
placeholder="Select date"
/>
</div>
</div>
<div class="column-2 w-100 w-100 d-flex justify-content-between">
<p class="w-25 fs-6 fw-bold">Opening and closing dates</p>
<div class="w-75 d-flex gap-3">
<input type="hidden" name="" />
<div id="dateRangePicker2" class="w-100"></div>
</div>
</div>
Answered By - Wongjn
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.