v-calendar does not highlight dates inside props when selected - javascript

I'm trying to highlight my vue calendar based on start and end dates that I select. I am following the documentation but it doesn't seem to provide much detail on how to select dates https://vcalendar.io/attributes.html
currently I am able to select dates and store them into my state using the dayClicked method but when I use the dates prop inside attributes to set the highlighted days nothing happens. I have noticed that if I just
replace
dates: { start: new Date(year, month, this.selectedDay.day), end: new Date(year, month, this.endDate.day)},
with
dates: { start: new Date(year, month, 12), end: new Date(year, month, 14)},
it works fine, but I have checked to make sure the values being passed are integers so I'm assuming it just doesn't have access to data() for some reason... I'm hoping someone can help me find a way around this problem and pass my days to the calendar component somehow
Any help is appreciated :)
<template>
<div id="calendarContainer">
<DatePicker is-range :attributes='attributes'
#dayclick='dayClicked'
/>
<button class="arrowBtnsLeft" #click="monthBack"><</button>
<button class="arrowBtnsRight" #click="monthForward">></button>
</div>
</template>
<script>
import DatePicker from 'v-calendar/lib/components/calendar.umd'
export default {
name: 'calendar',
components:{
DatePicker,
},
data() {
const date = new Date()
const year = date.getFullYear()
const month = date.getMonth()
return {
selectedDay: {day: 14},
endDate: {day: 17},
attributes: [
// This is a single attribute
{
key: 'today',
highlight:{
start: {fillMode: 'outline'},
end: {fillMode: 'outline'},
color:'red',
fillMod:'light'
},
dates: { start: new Date(year, month, this.selectedDay.day), end: new Date(year, month, this.endDate.day)},
}
]
}
},
onMounted(){
console.log(this.range)
},
methods: {
dayClicked(day) {
if(this.selectedDay == null){
this.selectedDay = day;
//change days styles to be blue
}else if(this.selectedDay!== null && this.endDate == null){
this.endDate = day;
//change days styles to be blue
//change days days inbetween to be outlined
console.log('start',this.selectedDay, 'end', this.endDate)
this.selectedDay.classes.push('start')
this.endDate.classes.push('end')
}else{
//remove classes for start and end
this.selectedDay.classes.pop()
this.endDate.classes.pop()
this.selectedDay = day;
this.endDate = null;
}
},
monthForward(){
let newtime = this.context.selectedYMD.split('-')
var timestring = ''
newtime[1] = parseInt(newtime[1])+1
newtime[1] = newtime[1].toString()
for( let i = 0; i < 3; i ++){
console.log(newtime[i])
if(i < 2){
timestring+=newtime[i]+'-'
}else{
timestring+=newtime[i]
}
}
this.value = timestring
},
monthBack(){
let newtime = this.context.selectedYMD.split('-')
var timestring = ''
newtime[1] = parseInt(newtime[1])-1
newtime[1] = newtime[1].toString()
for( let i = 0; i < 3; i ++){
console.log(newtime[i])
if(i < 2){
timestring+=newtime[i]+'-'
}else{
timestring+=newtime[i]
}
}
this.value = timestring
}
}
}
</script>
<style>
#calendarContainer{
position: relative;
z-index: 1;
width: 50%;
height: 50%;
}
.inTrip{
border-top:1px solid gray;
border-bottom:1px solid gray;
}
.start{
border-radius: 20px;
border-left:1px solid gray;
border-right:none;
background-color:#2E9CFF;
color:white;
}
.end{
border-radius: 20px;
border-right:1px solid gray;
border-left:none;
background-color:#2E9CFF;
color:white;
}
.arrowBtnsLeft{
position:absolute;
top:.8em;
left:12em;
background-color:#afd7f78e;
color:#2E9CFF;
border: none;
margin-left: .5em;
margin-right: .5em;
border-radius:5px;
text-align: center;
}
.arrowBtnsRight{
position:absolute;
top:.8em;
left:14em;
background-color:#afd7f78e;
color:#2E9CFF;
border: none;
margin-left: .5em;
margin-right: .5em;
border-radius:5px;
text-align: center;
}
</style>

if anyone is curious I found a solution, I used the computed properties to return 2 sets of days
<template>
<div id="calendarContainer">
<Calendar :attributes='attr' #dayclick='onDayClick' />
<button class="arrowBtnsLeft" #click="monthBack"><</button>
<button class="arrowBtnsRight" #click="monthForward">></button>
</div>
</template>
<script>
import Calendar from 'v-calendar/lib/components/calendar.umd'
export default {
name: 'calendar',
components:{
Calendar
},
data() {
return {
days : [],
counter: 0
};
},
computed:{
dates() {
return this.days.map(day => day.date);
},
attr() {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth();
return [this.dates.map(date => ({
highlight:{class:'start'},
dates: date,
})),
{
highlight:'blue',
dates: {
start: new Date(year, month, 1), end:new Date(year, month, 1)
}
}
];
},
},
methods: {
onDayClick(day) {
const idx = this.days.findIndex(d => d.id === day.id);
if(this.counter > 1 || this.days.length > 2){
this.days = []
this.counter = 0
}
this.counter+=1
if (idx >= 0) {
this.days.splice(idx, 1);
} else {
this.days.push({
id: day.id,
date: day.date,
})
if(this.days.length == 2){
this.attr[1].dates.start = this.days[0].date
this.attr[1].dates.end = day.date
}
}
console.log(this.days,'count',this.counter,'attributes',this.attr[1].dates,'days.length',this.days.length)
}
}
</script>

I know. it is a component that was written without regard to vueJS best practices or standards, I had to write a bunch of hacks like this to, just do ordinary things like hide the calendar.

Related

Modifying JS code to remove DatePicker option

I'm trying to add a datepicker to a page I'm creating. Since I don't know much at all about Javascript I'm modifying an example I've found at https://code-boxx.com/simple-datepicker-pure-javascript-css/. I don't want any extra pages or files as I need the form I'm creating to be entirely self-contained. I've condensed it down to this:
<!DOCTYPE html>
<html>
<head>
<title>Simple Date Picker Example</title>
<style>
/* (A) POPUP */
.picker-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.5);
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
}
.picker-wrap.show {
opacity: 1;
visibility: visible;
}
.picker-wrap .picker {
margin: 50vh auto 0 auto;
transform: translateY(-50%);
}
/* (B) CONTAINER */
.picker {
max-width: 300px;
background: #444444;
padding: 10px;
}
/* (C) MONTH + YEAR */
.picker-m, .picker-y {
width: 50%;
padding: 5px;
box-sizing: border-box;
font-size: 16px;
}
/* (D) DAY */
.picker-d table {
color: #fff;
border-collapse: separate;
width: 100%;
margin-top: 10px;
}
.picker-d table td {
width: 14.28%; /* 7 EQUAL COLUMNS */
padding: 5px;
text-align: center;
}
/* HEADER CELLS */
.picker-d-h td {
font-weight: bold;
}
/* BLANK DATES */
.picker-d-b {
background: #4e4e4e;
}
/* TODAY */
.picker-d-td {
background: #d84f4f;
}
/* PICKABLE DATES */
.picker-d-d:hover {
cursor: pointer;
/* UNPICKABLE DATES */
.picker-d-dd {
color: #888;
background: #4e4e4e;
}
</style>
<!-- (A) LOAD DATE PICKER -->
<!--<link href="dp-dark.css" rel="stylesheet">-->
<link href="dp-light.css" rel="stylesheet" />
<script src="datepicker.js"></script>
</head>
<body>
<!-- (B) THE HTML -->
<!-- (B1) INLINE DATE PICKER -->
<input type="text" id="input-inline" placeholder="Inline" />
<div id="pick-inline"></div>
<!-- (B2) POPUP DATE PICKER -->
<input type="text" id="input-pop" placeholder="Popup" />
<!-- (C) ATTACH DATE PICKER ON LOAD -->
<script>
window.addEventListener("load", function () {
// (C1) INLINE DATE PICKER
picker.attach({
target: "input-inline",
container: "pick-inline",
});
// (C2) POPUP DATE PICKER
picker.attach({
target: "input-pop",
});
});
</script>
</body>
<script>
var picker = {
// (A) ATTACH DATEPICKER TO TARGET
// target : datepicker will populate this field
// container : datepicker will be generated in this container
// startmon : start on Monday (default false)
// disableday : array of days to disable, e.g. [2,7] to disable Tue and Sun
attach: function (opt) {
// (A1) CREATE NEW DATEPICKER
var dp = document.createElement("div");
dp.dataset.target = opt.target;
dp.dataset.startmon = opt.startmon ? "1" : "0";
dp.classList.add("picker");
if (opt.disableday) {
dp.dataset.disableday = JSON.stringify(opt.disableday);
}
// (A2) DEFAULT TO CURRENT MONTH + YEAR - NOTE: UTC+0!
var today = new Date(),
thisMonth = today.getUTCMonth(), // Note: Jan is 0
thisYear = today.getUTCFullYear(),
months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
// (A3) MONTH SELECT
var select = document.createElement("select"),
option = null;
select.classList.add("picker-m");
for (var mth in months) {
option = document.createElement("option");
option.value = parseInt(mth) + 1;
option.text = months[mth];
select.appendChild(option);
}
select.selectedIndex = thisMonth;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A4) YEAR SELECT
var yRange = 10; // Year range to show, I.E. from thisYear-yRange to thisYear+yRange
select = document.createElement("select");
select.classList.add("picker-y");
for (var y = thisYear - yRange; y < thisYear + yRange; y++) {
option = document.createElement("option");
option.value = y;
option.text = y;
select.appendChild(option);
}
select.selectedIndex = yRange;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A5) DAY SELECT
var days = document.createElement("div");
days.classList.add("picker-d");
dp.appendChild(days);
// (A6) ATTACH DATE PICKER TO TARGET CONTAINER + DRAW THE DATES
picker.draw(select);
// (A6-I) INLINE DATE PICKER
if (opt.container) {
document.getElementById(opt.container).appendChild(dp);
}
// (A6-P) POPUP DATE PICKER
else {
// (A6-P-1) MARK THIS AS A "POPUP"
var uniqueID = 0;
while (document.getElementById("picker-" + uniqueID) != null) {
uniqueID = Math.floor(Math.random() * (100 - 2)) + 1;
}
dp.dataset.popup = "1";
dp.dataset.dpid = uniqueID;
// (A6-P-2) CREATE WRAPPER
var wrapper = document.createElement("div");
wrapper.id = "picker-" + uniqueID;
wrapper.classList.add("picker-wrap");
wrapper.appendChild(dp);
// (A6-P-3) ATTACH ONCLICK TO SHOW/HIDE DATEPICKER
var target = document.getElementById(opt.target);
target.dataset.dp = uniqueID;
target.readOnly = true; // Prevent onscreen keyboar on mobile devices
target.onfocus = function () {
document
.getElementById("picker-" + this.dataset.dp)
.classList.add("show");
};
wrapper.addEventListener("click", function (evt) {
if (evt.target.classList.contains("picker-wrap")) {
this.classList.remove("show");
}
});
// (A6-P-4) ATTACH POPUP DATEPICKER TO BODY
document.body.appendChild(wrapper);
}
},
// (B) DRAW THE DAYS IN MONTH
// el : HTML reference to either year or month selector
draw: function (el) {
// (B1) GET DATE PICKER COMPONENTS
var parent = el.parentElement,
year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
days = parent.getElementsByClassName("picker-d")[0];
// (B2) DATE RANGE CALCULATION - NOTE: UTC+0!
var daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
startDay = new Date(Date.UTC(year, month - 1, 1)).getUTCDay(), // Note: Sun = 0
endDay = new Date(Date.UTC(year, month - 1, daysInMonth)).getUTCDay(),
startDay = startDay == 0 ? 7 : startDay,
endDay = endDay == 0 ? 7 : endDay;
// (B3) GENERATE DATE SQUARES (IN ARRAY FIRST)
var squares = [],
disableday = null;
if (parent.dataset.disableday) {
disableday = JSON.parse(parent.dataset.disableday);
}
// (B4) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
if (parent.dataset.startmon == "1" && startDay != 1) {
for (var i = 1; i < startDay; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && startDay != 7) {
for (var i = 0; i < startDay; i++) {
squares.push("B");
}
}
// (B5) DAYS OF MONTH
// (B5-1) ALL DAYS ENABLED, JUST ADD
if (disableday == null) {
for (var i = 1; i <= daysInMonth; i++) {
squares.push([i, false]);
}
}
// (B5-2) SOME DAYS DISABLED
else {
var thisday = startDay;
for (var i = 1; i <= daysInMonth; i++) {
// CHECK IF DAY IS DISABLED
var disabled = disableday.includes(thisday);
// DAY OF MONTH, DISABLED
squares.push([i, disabled]);
// NEXT DAY
thisday++;
if (thisday == 8) {
thisday = 1;
}
}
}
// (B6) EMPTY SQUARES AFTER LAST DAY OF MONTH
if (parent.dataset.startmon == "1" && endDay != 7) {
for (var i = endDay; i < 7; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && endDay != 6) {
for (var i = endDay; i < (endDay == 7 ? 13 : 6); i++) {
squares.push("B");
}
}
// (B7) DRAW HTML
var daynames = ["Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
if (parent.dataset.startmon == "1") {
daynames.push("Sun");
} else {
daynames.unshift("Sun");
}
// (B7-1) HTML DATE HEADER
var table = document.createElement("table"),
row = table.insertRow(),
cell = null;
row.classList.add("picker-d-h");
for (let d of daynames) {
cell = row.insertCell();
cell.innerHTML = d;
}
// (B7-2) HTML DATE CELLS
var total = squares.length,
row = table.insertRow(),
today = new Date(),
todayDate = null;
if (
today.getUTCMonth() + 1 == month &&
today.getUTCFullYear() == year
) {
todayDate = today.getUTCDate();
}
for (var i = 0; i < total; i++) {
if (i != total && i % 7 == 0) {
row = table.insertRow();
}
cell = row.insertCell();
if (squares[i] == "B") {
cell.classList.add("picker-d-b");
} else {
cell.innerHTML = squares[i][0];
// NOT ALLOWED TO CHOOSE THIS DAY
if (squares[i][1]) {
cell.classList.add("picker-d-dd");
}
// ALLOWED TO CHOOSE THIS DAY
else {
if (i == todayDate) {
cell.classList.add("picker-d-td");
}
cell.classList.add("picker-d-d");
cell.addEventListener("click", function () {
picker.pick(this);
});
}
}
}
// (B7-3) ATTACH NEW CALENDAR TO DATEPICKER
days.innerHTML = "";
days.appendChild(table);
},
// (C) CHOOSE A DATE
// el : HTML reference to selected date cell
pick: function (el) {
// (C1) GET ALL COMPONENTS
var parent = el.parentElement;
while (!parent.classList.contains("picker")) {
parent = parent.parentElement;
}
// (C2) GET FULL SELECTED YEAR MONTH DAY
var year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
day = el.innerHTML;
// YYYY-MM-DD FORMAT - CHANGE FORMAT HERE IF YOU WANT !
if (parseInt(month) < 10) {
month = "0" + month;
}
if (parseInt(day) < 10) {
day = "0" + day;
}
var fullDate = year + "-" + month + "-" + day;
// (C3) UPDATE SELECTED DATE
document.getElementById(parent.dataset.target).value = fullDate;
// (C4) POPUP ONLY - CLOSE THE POPUP
if (parent.dataset.popup == "1") {
document
.getElementById("picker-" + parent.dataset.dpid)
.classList.remove("show");
}
},
};
</script>
</html>
Since I don't want the inline date picker and only want the pop-up date picker, I thought all I would need to do is remove this section:
<!-- (B1) INLINE DATE PICKER -->
<input type="text" id="input-inline" placeholder="Inline"/>
<div id="pick-inline"></div>
but when I do that the pop-up stops working as well. What do I need to change to remove the inline but just keep the pop-up?
You commented the template code for the inline date picker, but you have not commented the script for inline date picker.
Comment out the below code to make your solution working.
// Comment this code block in script
picker.attach({
target: "input-inline",
container: "pick-inline",
});
Why this was throwing error?
The datepicker was trying to find a target from dom having id input-inline. Since you have commented it out, it will not be available. Thats why it was stoping the execution of javascript. The code got broken there and the lines below that is not executed. This is why your popup date picker was also not working.
Working Fiddle
window.addEventListener("load", function () {
// (C1) INLINE DATE PICKER
// picker.attach({
// target: "input-inline",
// container: "pick-inline",
// });
// (C2) POPUP DATE PICKER
picker.attach({
target: "input-pop",
});
});
var picker = {
// (A) ATTACH DATEPICKER TO TARGET
// target : datepicker will populate this field
// container : datepicker will be generated in this container
// startmon : start on Monday (default false)
// disableday : array of days to disable, e.g. [2,7] to disable Tue and Sun
attach: function (opt) {
// (A1) CREATE NEW DATEPICKER
var dp = document.createElement("div");
dp.dataset.target = opt.target;
dp.dataset.startmon = opt.startmon ? "1" : "0";
dp.classList.add("picker");
if (opt.disableday) {
dp.dataset.disableday = JSON.stringify(opt.disableday);
}
// (A2) DEFAULT TO CURRENT MONTH + YEAR - NOTE: UTC+0!
var today = new Date(),
thisMonth = today.getUTCMonth(), // Note: Jan is 0
thisYear = today.getUTCFullYear(),
months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
// (A3) MONTH SELECT
var select = document.createElement("select"),
option = null;
select.classList.add("picker-m");
for (var mth in months) {
option = document.createElement("option");
option.value = parseInt(mth) + 1;
option.text = months[mth];
select.appendChild(option);
}
select.selectedIndex = thisMonth;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A4) YEAR SELECT
var yRange = 10; // Year range to show, I.E. from thisYear-yRange to thisYear+yRange
select = document.createElement("select");
select.classList.add("picker-y");
for (var y = thisYear - yRange; y < thisYear + yRange; y++) {
option = document.createElement("option");
option.value = y;
option.text = y;
select.appendChild(option);
}
select.selectedIndex = yRange;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A5) DAY SELECT
var days = document.createElement("div");
days.classList.add("picker-d");
dp.appendChild(days);
// (A6) ATTACH DATE PICKER TO TARGET CONTAINER + DRAW THE DATES
picker.draw(select);
// (A6-I) INLINE DATE PICKER
if (opt.container) {
document.getElementById(opt.container).appendChild(dp);
}
// (A6-P) POPUP DATE PICKER
else {
// (A6-P-1) MARK THIS AS A "POPUP"
var uniqueID = 0;
while (document.getElementById("picker-" + uniqueID) != null) {
uniqueID = Math.floor(Math.random() * (100 - 2)) + 1;
}
dp.dataset.popup = "1";
dp.dataset.dpid = uniqueID;
// (A6-P-2) CREATE WRAPPER
var wrapper = document.createElement("div");
wrapper.id = "picker-" + uniqueID;
wrapper.classList.add("picker-wrap");
wrapper.appendChild(dp);
// (A6-P-3) ATTACH ONCLICK TO SHOW/HIDE DATEPICKER
var target = document.getElementById(opt.target);
target.dataset.dp = uniqueID;
target.readOnly = true; // Prevent onscreen keyboar on mobile devices
target.onfocus = function () {
document
.getElementById("picker-" + this.dataset.dp)
.classList.add("show");
};
wrapper.addEventListener("click", function (evt) {
if (evt.target.classList.contains("picker-wrap")) {
this.classList.remove("show");
}
});
// (A6-P-4) ATTACH POPUP DATEPICKER TO BODY
document.body.appendChild(wrapper);
}
},
// (B) DRAW THE DAYS IN MONTH
// el : HTML reference to either year or month selector
draw: function (el) {
// (B1) GET DATE PICKER COMPONENTS
var parent = el.parentElement,
year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
days = parent.getElementsByClassName("picker-d")[0];
// (B2) DATE RANGE CALCULATION - NOTE: UTC+0!
var daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
startDay = new Date(Date.UTC(year, month - 1, 1)).getUTCDay(), // Note: Sun = 0
endDay = new Date(Date.UTC(year, month - 1, daysInMonth)).getUTCDay(),
startDay = startDay == 0 ? 7 : startDay,
endDay = endDay == 0 ? 7 : endDay;
// (B3) GENERATE DATE SQUARES (IN ARRAY FIRST)
var squares = [],
disableday = null;
if (parent.dataset.disableday) {
disableday = JSON.parse(parent.dataset.disableday);
}
// (B4) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
if (parent.dataset.startmon == "1" && startDay != 1) {
for (var i = 1; i < startDay; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && startDay != 7) {
for (var i = 0; i < startDay; i++) {
squares.push("B");
}
}
// (B5) DAYS OF MONTH
// (B5-1) ALL DAYS ENABLED, JUST ADD
if (disableday == null) {
for (var i = 1; i <= daysInMonth; i++) {
squares.push([i, false]);
}
}
// (B5-2) SOME DAYS DISABLED
else {
var thisday = startDay;
for (var i = 1; i <= daysInMonth; i++) {
// CHECK IF DAY IS DISABLED
var disabled = disableday.includes(thisday);
// DAY OF MONTH, DISABLED
squares.push([i, disabled]);
// NEXT DAY
thisday++;
if (thisday == 8) {
thisday = 1;
}
}
}
// (B6) EMPTY SQUARES AFTER LAST DAY OF MONTH
if (parent.dataset.startmon == "1" && endDay != 7) {
for (var i = endDay; i < 7; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && endDay != 6) {
for (var i = endDay; i < (endDay == 7 ? 13 : 6); i++) {
squares.push("B");
}
}
// (B7) DRAW HTML
var daynames = ["Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
if (parent.dataset.startmon == "1") {
daynames.push("Sun");
} else {
daynames.unshift("Sun");
}
// (B7-1) HTML DATE HEADER
var table = document.createElement("table"),
row = table.insertRow(),
cell = null;
row.classList.add("picker-d-h");
for (let d of daynames) {
cell = row.insertCell();
cell.innerHTML = d;
}
// (B7-2) HTML DATE CELLS
var total = squares.length,
row = table.insertRow(),
today = new Date(),
todayDate = null;
if (
today.getUTCMonth() + 1 == month &&
today.getUTCFullYear() == year
) {
todayDate = today.getUTCDate();
}
for (var i = 0; i < total; i++) {
if (i != total && i % 7 == 0) {
row = table.insertRow();
}
cell = row.insertCell();
if (squares[i] == "B") {
cell.classList.add("picker-d-b");
} else {
cell.innerHTML = squares[i][0];
// NOT ALLOWED TO CHOOSE THIS DAY
if (squares[i][1]) {
cell.classList.add("picker-d-dd");
}
// ALLOWED TO CHOOSE THIS DAY
else {
if (i == todayDate) {
cell.classList.add("picker-d-td");
}
cell.classList.add("picker-d-d");
cell.addEventListener("click", function () {
picker.pick(this);
});
}
}
}
// (B7-3) ATTACH NEW CALENDAR TO DATEPICKER
days.innerHTML = "";
days.appendChild(table);
},
// (C) CHOOSE A DATE
// el : HTML reference to selected date cell
pick: function (el) {
// (C1) GET ALL COMPONENTS
var parent = el.parentElement;
while (!parent.classList.contains("picker")) {
parent = parent.parentElement;
}
// (C2) GET FULL SELECTED YEAR MONTH DAY
var year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
day = el.innerHTML;
// YYYY-MM-DD FORMAT - CHANGE FORMAT HERE IF YOU WANT !
if (parseInt(month) < 10) {
month = "0" + month;
}
if (parseInt(day) < 10) {
day = "0" + day;
}
var fullDate = year + "-" + month + "-" + day;
// (C3) UPDATE SELECTED DATE
document.getElementById(parent.dataset.target).value = fullDate;
// (C4) POPUP ONLY - CLOSE THE POPUP
if (parent.dataset.popup == "1") {
document
.getElementById("picker-" + parent.dataset.dpid)
.classList.remove("show");
}
},
};
/* (A) POPUP */
.picker-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
}
.picker-wrap.show {
opacity: 1;
visibility: visible;
}
.picker-wrap .picker {
margin: 50vh auto 0 auto;
transform: translateY(-50%);
}
/* (B) CONTAINER */
.picker {
max-width: 300px;
background: #444444;
padding: 10px;
}
/* (C) MONTH + YEAR */
.picker-m,
.picker-y {
width: 50%;
padding: 5px;
box-sizing: border-box;
font-size: 16px;
}
/* (D) DAY */
.picker-d table {
color: #fff;
border-collapse: separate;
width: 100%;
margin-top: 10px;
}
.picker-d table td {
width: 14.28%;
/* 7 EQUAL COLUMNS */
padding: 5px;
text-align: center;
}
/* HEADER CELLS */
.picker-d-h td {
font-weight: bold;
}
/* BLANK DATES */
.picker-d-b {
background: #4e4e4e;
}
/* TODAY */
.picker-d-td {
background: #d84f4f;
}
/* PICKABLE DATES */
.picker-d-d:hover {
cursor: pointer;
/* UNPICKABLE DATES */
.picker-d-dd {
color: #888;
background: #4e4e4e;
}
}
<!-- (B) THE HTML -->
<!-- (B1) INLINE DATE PICKER -->
<!-- <input type="text" id="input-inline" placeholder="Inline" />
<div id="pick-inline"></div> -->
<!-- (B2) POPUP DATE PICKER -->
<input type="text" id="input-pop" placeholder="Popup" />

Adding class via js

I have checked some questions about the same thing, but they didnt help me. Here is my code, what is wrong here? It does properly add the class, but not show changes at website.
//html
<div class="days"></div>
//css
.AddedClass {
background-color: #27ae60;
color: #fff;
}
//js
let today = new Date();
let endDate = new Date(
dt.getFullYear(),
dt.getMonth() + 1,
0
).getDate();
let cells = "";
for (let i = 1; i <= endDate; i++) {
if (!(i === today.getDate() && dt.getMonth() === today.getMonth() && dt.getFullYear() === today.getFullYear())) {
cells += `<div onclick='dayChanger(this);' data-value='${i}'>${i}</div>`;
} else {
cells += `<div class='today' onclick='dayChanger(this);' data-value='${i}'>${i}</div>`;
}
}
document.getElementsByClassName("days")[0].innerHTML = cells;
function dayChanger(obj) {
obj.classList.add('AddedClass');
dt.setDate(obj.getAttribute('data-value'));
}
Here's a simplified and working version of your code
function classAdding(obj) {
obj.classList.add('today');
}
.today {
background-color: #27ae60;
color: #fff;
}
<div onclick="classAdding(this)">something</div>
Try this
const myDiv = document.querySelector('.today').onclick = function () {
this.classList.add('todayNew');
}
.todayNew {
background-color: #27ae60;
color: red;
}
<div class="today">Value</div>

Is it possible to override a clock function so I could change its hours?

I'm designing a small browser project where you pick a city from the list and it presents you with the current time in city of your choice.
Although I've come across a problem.
The code only shows the correct time for a brief moment and then returns to the original UTC Standard time. The problem comes up at the "setTimeout" bit. Is there a possibility to override this? By adding clearTimeout perhaps?
function utcStandard(offset) {
var date = new Date();
var hh = date.getUTCHours();
var mm = date.getUTCMinutes();
var ss = date.getUTCSeconds();
if (offset != undefined) {
hh += offset
};
hh = checkTime(hh);
mm = checkTime(mm);
ss = checkTime(ss);
document.getElementById("time").innerHTML =
hh + ":" + mm + ":" + ss;
var t = setTimeout(utcStandard, 500);
function checkTime(i) {
if (i < 10) {
i = "0" + i
};
return i;
}
}
I decided to add the function to each item in the HTML list. For example.
<ul>
<li>Amsterdam</li>
</ul>
Like this - it is shorter and uses UTC where it is needed
I changed to minutes so you can have 5:30 for India for example
I did not consider DST for now
const pad = (num) => ("0"+num).slice(-2);
let t;
let curOffset = 0;
const reset = (offset) => {
clearInterval(t);
curOffset = offset ? offset : curOffset;
t = setInterval(utcStandard,500);
return false;
};
const utcStandard = () => {
var date = new Date(new Date().toUTCString().substr(0, 25))
date.setMinutes(date.getMinutes()+curOffset);
const hh = pad(date.getHours());
const mm = pad(date.getMinutes());
const ss = pad(date.getSeconds());
document.getElementById("time").innerHTML = "" + hh + ":" + mm + ":" + ss;
};
reset(0);
<span id="time"></span>
<ul>
<li>Amsterdam</li>
<li>London</li>
<li>Kolkata</li>
</ul>
The following implementation has two pieces of state:
dateString - the string representation of the time
offset - the currently chosen time offset
tick updates dateString repeatedly to capture the passage of time.
render renders the dateString to the DOM using requestAnimationFrame.
const freeze = Object.freeze
const DTF = new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
let state = freeze({
dateString: '00:00:00',
offset: 0
})
function setOffset(o) {
clearTimeout(tickId)
state = freeze({ ...state, offset: o })
tick()
}
function toDateString(date = new Date) {
const d = DTF.formatToParts(date)
return `${d[0].value}:${d[2].value}:${d[4].value}`
}
let tickId = null
function tick() {
const date = new Date
date.setHours(date.getHours() + state.offset)
const dateString = toDateString(date)
tickId = setTimeout(tick, 16)
if(dateString !== state.dateString)
state = freeze({ ...state, dateString })
}
function render(state) {
document.getElementById('time').innerText = state.dateString
}
let previousState = null
function loop() {
if(state !== previousState) {
previousState = state
render(state)
}
requestAnimationFrame(loop)
}
tick()
requestAnimationFrame(loop)
input[type="radio"] {
display: none;
}
label {
font-family: sans-serif;
padding: 10px;
margin: 10px;
display: block;
cursor: pointer;
border-radius: 5px;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
input[type="radio"]+label {
background-color: rgba(0,220,220,0);
transition: background-color .5s ease-out 0s;
}
input[type="radio"]:checked+label {
background-color: rgba(0,220,220,1);
}
#time {
width: 100%;
font-family: sans-serif;
font-size: 2em;
text-align: center;
}
<input type="radio" name="group1" id="london" checked>
<label for="london" onclick="setOffset(0)">London</label>
<input type="radio" name="group1" id="amsterdam">
<label for="amsterdam" onclick="setOffset(1)">Amsterdam</label>
<input type="radio" name="group1" id="new-york">
<label for="new-york" onclick="setOffset(-4)">New York</label>
<div id="time"></div>

Changing the direction of content on calendar design

I'm building my own version of dynamic calendar with html css and js.
I got two issues:
Small issue: The buttons of changing to the next / previous month work as expected just after the second click.
Major issue: I can't understand how to fill last month's days on the right ("from the end") direction.
This is my code:
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
var monthnames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
var today = new Date();
document.querySelector('#monthChoose').value = (today.getMonth()+1);
document.querySelector('#yearChoose').value = today.getFullYear();
// next and previous buttons
document.querySelector('#nextM').addEventListener('click', function() { document.querySelector('#monthChoose').value = operator++; buildCalendar()});
document.querySelector('#prevM').addEventListener('click', function() {document.querySelector('#monthChoose').value = operator--; buildCalendar()});
// fill days of the week as title
for (var i=0; i < days.length; i++) {
document.querySelector('#weekdays').innerHTML += '<li><span>'+days[i]+'</span></li>';
}
var operator = document.querySelector('#monthChoose').value; // this will later on the function to restrict input value
function buildCalendar() {
if (operator > 12) {operator = 1};
if (operator < 1) {operator = 12};
document.querySelector('#days').innerHTML = ' '; // clear records
var month = document.querySelector('#monthChoose').value;
var year = document.querySelector('#yearChoose').value;
document.querySelector('#monthName').textContent = monthnames[month-1]; // display month name
function daysInMonth (month, year) { return new Date(year, month, 0).getDate(); } // constructor to get number of days in chosen month
var lastMonthDays = daysInMonth(month-1, year);
var currentMonthDays = daysInMonth(month, year);
var currentFirstDay = new Date(year, month-1 ,1);
currentFirstDayNum = new Date(currentFirstDay).getDay();
var currentLastDay = new Date(year, month ,1);
currentLastDayNum = new Date(currentLastDay).getDay();
// fill last month's days
// this cause issue: i need to change the content direction so it will fill from the opposite direction
for (var i=0; i < currentFirstDayNum; i++) {
document.querySelector('#days').innerHTML += '<li style="opacity: 0.5;">'+(lastMonthDays-i)+'</li>';
}
// fill the current month days
for (var i=0; i < currentMonthDays; i++) {
document.querySelector('#days').innerHTML += '<li>'+(i+1)+'</li>';
}
// fill the rest of the board
var liLength = document.querySelectorAll('#days > li').length;
var restOfBoard=0;
while (liLength < 42) {
restOfBoard+=1;
document.querySelector('#days').innerHTML += '<li style="opacity: 0.5;">'+restOfBoard+'</li>';
liLength++
}
}
buildCalendar();
ul {list-style-type: none; text-align: center; margin: 0; padding: 0;}
#month {padding: 30px 0; width: 100%; }
#month li input:first-child { display: none; } /* hide input that control months - will change with js*/
#monthName { display: block; }
#monthName { font-size: 2em; }
#month button {width: auto; padding: 0; font-size: 2em;}
#month #prevM {float: left;}
#month #nextM {float: right;}
#weekdays { padding: 10px 0; background-color: gray; }
#weekdays li {
display: inline-block;
color: white;
width: calc(100% / 7);
}
#days { padding: 10px 0; }
#days li {
display: inline-block;
width: calc(100% / 7);
height: calc(400px / 5);
}
<ul id="month">
<li><button id="prevM">❮</button> </li>
<li><button id="nextM">❯</button> </li>
<li id="monthName"></li>
<li>
<input type="number" id="monthChoose" onchange="buildCalendar()" />
<input type="number" id="yearChoose" onchange="buildCalendar()"/>
</li>
</ul>
<ul id="weekdays"></ul>
<ul id="days"></ul>
Note: will glad to hear about things i could do better with this code...
EDIT:
The expected result for the second issue is the lest days of last month. If we take October 2019: the first day is Tuesday so on this week Monday should be the 30th and Sunday the 29th. Can't understand how to fill those days in this order dynamically.
So i finally managed to solve the second problem: Gave the lastMonthDays a unique class, sort it by it content, append the sorting elements, and then proceed with the rest of code.
For this i modified this script for my needs.
Thanks everybody.
The first problem is quite easy to solve by changing
document.querySelector('#monthChoose').value = operator++;
to
document.querySelector('#monthChoose').value = ++operator;
and changing
document.querySelector('#monthChoose').value = operator--;
to
document.querySelector('#monthChoose').value = --operator;
Putting ++ after operator means you don't increase the value of operator until afer you copy its value to the "monthChoose" element, where as putting it beforehand ensures you change its value first. And of course you later use the "monthChoose" element's value to determine the actual month to be displayed.
N.B. It's unclear why you actually need two values here at all - that is just a recipe for confusion. Since operator is global, you could just use that all the way through. Alternatively you could use the "monthChoose" element to maintain state if you want to reduce your use of global variables (which generally, you should).
Here's a demo:
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var monthnames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var today = new Date();
document.querySelector('#monthChoose').value = (today.getMonth() + 1);
document.querySelector('#yearChoose').value = today.getFullYear();
// next and previous buttons
document.querySelector('#nextM').addEventListener('click', function() {
document.querySelector('#monthChoose').value = ++operator;
buildCalendar()
});
document.querySelector('#prevM').addEventListener('click', function() {
document.querySelector('#monthChoose').value = --operator;
buildCalendar()
});
// fill days of the week as title
for (var i = 0; i < days.length; i++) {
document.querySelector('#weekdays').innerHTML += '<li><span>' + days[i] + '</span></li>';
}
var operator = document.querySelector('#monthChoose').value; // this will later on the function to restrict input value
function buildCalendar() {
if (operator > 12) {
operator = 1
};
if (operator < 1) {
operator = 12
};
document.querySelector('#days').innerHTML = ' '; // clear records
var month = document.querySelector('#monthChoose').value;
var year = document.querySelector('#yearChoose').value;
document.querySelector('#monthName').textContent = monthnames[month - 1]; // display month name
function daysInMonth(month, year) {
return new Date(year, month, 0).getDate();
} // constructor to get number of days in chosen month
var lastMonthDays = daysInMonth(month - 1, year);
var currentMonthDays = daysInMonth(month, year);
var currentFirstDay = new Date(year, month - 1, 1);
currentFirstDayNum = new Date(currentFirstDay).getDay();
var currentLastDay = new Date(year, month, 1);
currentLastDayNum = new Date(currentLastDay).getDay();
// fill last month's days
// this cause issue: i need to change the content direction so it will fill from the opposite direction
for (var i = 0; i < currentFirstDayNum; i++) {
document.querySelector('#days').innerHTML += '<li style="opacity: 0.5;">' + (lastMonthDays - i) + '</li>';
}
// fill the current month days
for (var i = 0; i < currentMonthDays; i++) {
document.querySelector('#days').innerHTML += '<li>' + (i + 1) + '</li>';
}
// fill the rest of the board
var liLength = document.querySelectorAll('#days > li').length;
var restOfBoard = 0;
while (liLength < 42) {
restOfBoard += 1;
document.querySelector('#days').innerHTML += '<li style="opacity: 0.5;">' + restOfBoard + '</li>';
liLength++
}
}
buildCalendar();
ul {
list-style-type: none;
text-align: center;
margin: 0;
padding: 0;
}
#month {
padding: 30px 0;
width: 100%;
}
#month li input:first-child {
display: none;
}
/* hide input that control months - will change with js*/
#monthName {
display: block;
}
#monthName {
font-size: 2em;
}
#month button {
width: auto;
padding: 0;
font-size: 2em;
}
#month #prevM {
float: left;
}
#month #nextM {
float: right;
}
#weekdays {
padding: 10px 0;
background-color: gray;
}
#weekdays li {
display: inline-block;
color: white;
width: calc(100% / 7);
}
#days {
padding: 10px 0;
}
#days li {
display: inline-block;
width: calc(100% / 7);
height: calc(400px / 5);
}
<ul id="month">
<li><button id="prevM">❮</button> </li>
<li><button id="nextM">❯</button> </li>
<li id="monthName"></li>
<li>
<input type="number" id="monthChoose" onchange="buildCalendar()" />
<input type="number" id="yearChoose" onchange="buildCalendar()" />
</li>
</ul>
<ul id="weekdays"></ul>
<ul id="days"></ul>
I'm afraid I don't understand precisely what you mean by your second problem. Perhaps you can give a clearer description / diagram showing what you want to happen and then I can update this answer?

add class if date is today

I have some boxes that represent the squares in an advent calendar. I've defined the date for each box in the data attribute which I'm using to compare against the current day. I'm trying to add a class 'today' to the box that represents the current day. I've created a fiddle to demonstrate this. How can I fix it so that today class is added to the appropriate box?
JSFiddle
$(function() {
var currentDate = Date.now();
$(".grid-item").each(function() {
var specifiedDate = $(this).data('date');
var date = Date.parse(specifiedDate);
if (!isNaN(date) == currentDate) {
$(this).addClass('today');
}
else if(!isNaN(date) && currentDate - date > 0) {
$(this).addClass('past');
}
else {
$(this).addClass('future');
}
});
});
You don't have to use Date.now() as this doesn't outputs the dates similar to the data attributes have. Instead you have to create current date as this and check in the conditions like:
$(function() {
var date = new Date(),
currentDate = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
$(".grid-item").each(function() {
var specifiedDate = $(this).data('date');
if (specifiedDate == currentDate) {
$(this).addClass('today');
} else if (currentDate > specifiedDate) {
$(this).addClass('past');
} else {
$(this).addClass('future');
}
});
});
.grid-item {
height: 170px;
width: 170px;
float: left;
background: red;
margin: 10px;
}
.today {
background: yellow;
border: red 1px solid;
}
.past {
background: black;
border: red 1px solid;
}
.future {
background: blue;
border: red 1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="grid-item" data-date="2015-11-23">
</div>
<div class="grid-item" data-date="2015-11-24">
</div>
<div class="grid-item" data-date="2015-11-25">
</div>
<div class="grid-item" data-date="2015-11-26">
</div>
<div class="grid-item" data-date="2015-11-27">
</div>
<div class="grid-item" data-date="2015-11-28">
</div>
<div class="grid-item" data-date="2015-11-29">
</div>
You can add class to current date using following jquery, just replace your jquery with following :-
$(function() {
var d =new Date();
var curmonth = d.getMonth()+1;
var curDate = d.getFullYear()+"-"+curmonth+"-"+d.getDate();
$(".grid-item[data-date="+curDate+"]").addClass("today");
});
A possible solution
jsfiddle
$(function() {
var currentDate = Date.now();
var a = new Date(currentDate);
$(".grid-item").each(function() {
var specifiedDate = $(this).data('date');
var date = Date.parse(specifiedDate);
var b = new Date(date);
if (!isNaN(b) && b.getMonth() == a.getMonth() && b.getDay()== a.getDay() && b.getYear() == a.getYear()) {
$(this).addClass('today');
}
else if(!isNaN(b) && a - b > 0) {
$(this).addClass('past');
}
else {
$(this).addClass('future');
}
});
});
See this JSFiddle
JavaScript
$(function() {
var currentDate = Date.parse((new Date()).toLocaleDateString());
$(".grid-item").each(function() {
var specifiedDate = $(this).data('date');
var date = Date.parse(specifiedDate);
if (!isNaN(date) && date == currentDate) {
$(this).addClass('today');
}
else if(!isNaN(date) && currentDate - date > 0) {
$(this).addClass('past');
}
else {
$(this).addClass('future');
}
});
});
There is a single mistake in your code. Date.now() gives you the current timestamp in milliseconds. While you have a date in the data-date which will not match in any case. Correct way will be to compare the date instead of timestamps. Or just take the date without the time for comparison
The easiest solution would be to create new Date() object, and set it's hours, minutes and seconds to 0 like that:
currentDate = new Date();
currentDate.setHours(0);
currentDate.setMinutes(0);
currentDate.setSeconds(0);
and then:
var date = new Date(specifiedDate);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
Note that I am also setting date's hours, minutes and second to 0 due timezones (this can be fixed, but as I said, it seems to be the easiest way)
Or you can simply use :
$(function() {
$(".grid-item").each(function() {
$('.grid-item').eq(new Date().getDay()-1).addClass('today');
});
});
FIDDLE
Try This code
$(function() {
var currentDate = new Date();
$(".grid-item").each(function() {
var specifiedDate = $(this).data('date');
var date = new Date(specifiedDate);
if(date.setHours(0,0,0,0) == currentDate.setHours(0,0,0,0)){
$(this).addClass('today');
}
});
});
this code works for me last day. hope this helps you..
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10){
dd='0'+dd
}
if(mm<10){
mm='0'+mm
}
var today = yyyy+'-'+mm+'-'+dd;
if (date == today) {
$(this).addClass('today');
}
make sure two dates are same format..

Categories