I make a datepicker on vue3, When choosing two dates, I need the days between the selected dates to be hover. I use the "indexOf" method, but the desired result is not obtained
<div
v-for="date in daysInMonth(currentYear, currentMonthInNumber, firstDay, lastDay)"
:key="date"
ref="date"
class="day"
:class="{ active: date === firstDay || date === lastDay, between: between.indexOf(date)}"
#click="choosingDates(date)" > {{ date }} </div>
<script>
firstDay: false,
between: [],
lastDay: false,
firstDaySelected: false,
};
},
methods: {
choosingDates(date) {
if (this.firstDay === false) {
this.firstDay = date;
} else if (this.lastDay === false) {
this.lastDay = date;;
}
},
With this code, "between" hover all days of the month (css styles are written)
:class="{ between: between.indexOf(date)} "
what i do wrong
Try this :
<template>
<div class="datepicker">
<div class="month-header">
<i class="prev-month" #click="prevMonth"></i>
{{ currentMonth }} {{ currentYear }}
<i class="next-month" #click="nextMonth"></i>
</div>
<div class="weekdays">
<div class="weekday" v-for="weekday in weekdays" :key="weekday">
{{ weekday }}
</div>
</div>
<div class="days">
<div
v-for="date in daysInMonth(
currentYear,
currentMonthInNumber,
firstDay,
lastDay
)"
:key="date"
class="day"
:class="{
active: date === firstDay || date === lastDay,
between: between.includes(date),
}"
#click="chooseDate(date)"
>
{{ date }}
</div>
</div>
{{ between }}
</div>
</template>
<script>
export default {
data() {
return {
weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
],
currentMonth: "",
currentMonthInNumber: "",
currentYear: "",
firstDay: false,
between: [],
lastDay: false,
};
},
mounted() {
const date = new Date();
this.currentMonth = this.months[date.getMonth()];
this.currentMonthInNumber = date.getMonth();
this.currentYear = date.getFullYear();
},
methods: {
prevMonth() {
this.currentMonthInNumber--;
if (this.currentMonthInNumber < 0) {
this.currentMonthInNumber = 11;
this.currentYear--;
}
this.currentMonth = this.months[this.currentMonthInNumber];
},
nextMonth() {
this.currentMonthInNumber++;
if (this.currentMonthInNumber > 11) {
this.currentMonthInNumber = 0;
this.currentYear++;
}
this.currentMonth = this.months[this.currentMonthInNumber];
},
daysInMonth(year, month, firstDay, lastDay) {
let date = new Date(year, month, 1);
let days = [];
while (date.getMonth() === month) {
days.push(date.getDate());
date.setDate(date.getDate() + 1);
}
return days;
},
chooseDate(date) {
if (this.firstDay === false) {
this.firstDay = date;
} else if (this.lastDay === false) {
this.lastDay = date;
this.setBetween();
} else {
this.firstDay = date;
this.lastDay = false;
this.between = [];
}
},
setBetween() {
if (this.firstDay > this.lastDay) {
[this.firstDay, this.lastDay] = [this.lastDay, this.firstDay];
}
let date = new Date(
this.currentYear,
this.currentMonthInNumber,
this.firstDay
);
while (date.getDate() <= this.lastDay) {
this.between.push(date.getDate());
date.setDate(date.getDate() + 1);
}
},
},
};
</script>
<style scoped>
.datepicker {
background-color: #fff;
border-radius: 5px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
padding: 20px;
text-align: center;
}
.month-header {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.prev-month,
.next-month {
cursor: pointer;
}
.weekdays {
display: flex;
}
.weekday {
flex: 1;
font-weight: bold;
padding: 10px 0;
}
.days {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px;
margin-top: 20px;
}
.day {
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
cursor: pointer;
height: 40px;
line-height: 40px;
text-align: center;
user-select: none;
}
.day.active {
background-color: #3c8dbc;
color: #fff;
}
.day.between {
background-color: #ddd;
}
</style>
Related
NOTE-I'm new to JS and in this code, 24 hour clock runs and when I tap on 12 hour clock format
button it won't replace with 24 hour clock format. basically the button wont work or it wont
replace the clock format plz help
I used a window. Onload function which runs the 24 hour format clock and when I tap on 12 hour format clock button it wont replace
just run the code u'll understand what I mean
the only thing I want to achieve in this code is a clock which have two button 1st:12 hour format 2nd:24 hour format,
to change clock format on a tap
window.onload = (event) => {
clock_24();
};
function clock_24() {
let a;
let date;
let time;
const options = {
day: 'numeric',
month: 'long',
year: 'numeric'
};
setInterval(() => {
a = new Date();
date = a.toLocaleDateString(undefined, options);
let hours = String(a.getHours()).padStart(2, '0');
let min = String(a.getMinutes()).padStart(2, '0');
let sec = String(a.getSeconds()).padStart(2, '0');
let milli = a.getMilliseconds();
time = hours + ':' + min + ':' + sec + ':' + milli;
document.getElementById('time').innerHTML = time
document.getElementById('date').innerHTML = date
}, 1);
// foramt-change
document.getElementById("format").innerHTML = "24 Hour format";
document.getElementById("format").style.fontSize = "32px";
document.getElementById("format").style.fontfamily = 'Times New Roman';
console.log('24_loaded');
}
// onclick - event-12-hour-format-clock
// time-12f
function clock_12() {
setInterval(() => {
var date = new Date();
var hh_12 = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
var session_12 = date.getHours() >= 12 ? "PM" : "AM";
hh_12 = hh_12 < 10 ? "0" + hh_12 : hh_12;
var mm_12 = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
var ss_12 = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
tt_12 = hh_12 + ":" + mm_12 + ":" + ss_12 + " " + session_12;
document.getElementById('time').innerHTML = tt_12
// date-12f
const options = {
day: 'numeric',
month: 'long',
year: 'numeric'
};
date = date.toLocaleDateString(undefined, options);
document.getElementById('date').innerHTML = date
}, 1000);
// foramt-change
document.getElementById("format").innerHTML = "12 Hour format";
document.getElementById("format").style.fontSize = "32px";
document.getElementById("format").style.fontfamily = 'Times New Roman';
console.log('12_loaded');
}
* {
margin: 0;
padding: 0;
}
.t-d-cont {
background-color: gray;
margin: 50px;
padding: 50px;
}
#format {
border-left: 2px solid rgb(70, 166, 239);
margin-bottom: 20px;
padding-left: 20px;
font-weight: bold;
}
.redline {
border-left: 2px solid red;
width: 100%;
padding-left: 20px;
}
.time-box {
margin-bottom: 50px;
}
#time {
font-family: 'Rokkitt', serif;
font-size: 45px;
}
.date-box {
margin-bottom: 30px;
}
#date {
font-family: 'Rokkitt', serif;
font-size: 45px;
}
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropbtn-2 {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
margin-left: 15px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- font link -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Rokkitt:wght#100&display=swap" rel="stylesheet">
</head>
<body>
<!-- time and date container -->
<div class="t-d-cont">
<div id="format">
<h1>24 Hour format</h1>
</div>
<div class="redline ">
<div class="time-box">
<h1>Current Time: <span id="time"></span></h1>
</div>
<div class="date-box">
<h1> Today's Date: <span id="date"></span></h1>
</div>
</div>
<!-- 24 hour-button -->
<div class="dropdown">
<button class="dropbtn-2" onclick="clock_24();">24-hour-format</button>
</div>
<!-- 12 hour-button -->
<div class="dropdown">
<button class="dropbtn" onclick="clock_12();">12-hour-format</button>
</div>
</div>
</body>
</div>
</html>
When you switch the clocks, you need to stop the interval timer that's displaying using the previous format. Otherwise they both keep running, and one will overwrite the other.
Use a variable outside the functions to hold the current interval timer ID, so you can stop it with clearInterval().
window.onload = (event) => {
clock_24();
};
let timer;
function clock_24() {
let a;
let date;
let time;
const options = {
day: 'numeric',
month: 'long',
year: 'numeric'
};
clearInterval(timer);
timer = setInterval(() => {
a = new Date();
date = a.toLocaleDateString(undefined, options);
let hours = String(a.getHours()).padStart(2, '0');
let min = String(a.getMinutes()).padStart(2, '0');
let sec = String(a.getSeconds()).padStart(2, '0');
let milli = a.getMilliseconds();
time = hours + ':' + min + ':' + sec + ':' + milli;
document.getElementById('time').innerHTML = time
document.getElementById('date').innerHTML = date
}, 1);
// foramt-change
document.getElementById("format").innerHTML = "24 Hour format";
document.getElementById("format").style.fontSize = "32px";
document.getElementById("format").style.fontfamily = 'Times New Roman';
console.log('24_loaded');
}
// onclick - event-12-hour-format-clock
// time-12f
function clock_12() {
clearInterval(timer);
timer = setInterval(() => {
var date = new Date();
var hh_12 = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
var session_12 = date.getHours() >= 12 ? "PM" : "AM";
hh_12 = hh_12 < 10 ? "0" + hh_12 : hh_12;
var mm_12 = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
var ss_12 = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
tt_12 = hh_12 + ":" + mm_12 + ":" + ss_12 + " " + session_12;
document.getElementById('time').innerHTML = tt_12
// date-12f
const options = {
day: 'numeric',
month: 'long',
year: 'numeric'
};
date = date.toLocaleDateString(undefined, options);
document.getElementById('date').innerHTML = date
}, 1000);
// foramt-change
document.getElementById("format").innerHTML = "12 Hour format";
document.getElementById("format").style.fontSize = "32px";
document.getElementById("format").style.fontfamily = 'Times New Roman';
console.log('12_loaded');
}
* {
margin: 0;
padding: 0;
}
.t-d-cont {
background-color: gray;
margin: 50px;
padding: 50px;
}
#format {
border-left: 2px solid rgb(70, 166, 239);
margin-bottom: 20px;
padding-left: 20px;
font-weight: bold;
}
.redline {
border-left: 2px solid red;
width: 100%;
padding-left: 20px;
}
.time-box {
margin-bottom: 50px;
}
#time {
font-family: 'Rokkitt', serif;
font-size: 45px;
}
.date-box {
margin-bottom: 30px;
}
#date {
font-family: 'Rokkitt', serif;
font-size: 45px;
}
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropbtn-2 {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
margin-left: 15px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- font link -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Rokkitt:wght#100&display=swap" rel="stylesheet">
</head>
<body>
<!-- time and date container -->
<div class="t-d-cont">
<div id="format">
<h1>24 Hour format</h1>
</div>
<div class="redline ">
<div class="time-box">
<h1>Current Time: <span id="time"></span></h1>
</div>
<div class="date-box">
<h1> Today's Date: <span id="date"></span></h1>
</div>
</div>
<!-- 24 hour-button -->
<div class="dropdown">
<button class="dropbtn-2" onclick="clock_24();">24-hour-format</button>
</div>
<!-- 12 hour-button -->
<div class="dropdown">
<button class="dropbtn" onclick="clock_12();">12-hour-format</button>
</div>
</div>
</body>
</div>
</html>
I want to create a weekly calendar which display the current week and has two buttons nextweek and previousweek. Im able to move to the nextweek, but Im struggling with previousweek button. Need some suggestions for the same. I have used HTML, CSS and Javascript. Im struggling with the logic of previousweek button.
const date = new Date();
function renderCalendar(lastdayofweek)
{
var lastofweek = lastdayofweek;
date.setDate(1);
const monthDays = document.querySelector(".days");
var lastDay = new Date( date.getFullYear(), date.getMonth() + 1, 0).getDate();
const prevLastDay = new Date( date.getFullYear(), date.getMonth(), 0 ).getDate();
const firstDayIndex = date.getDay();
const lastDayIndex = new Date( date.getFullYear(), date.getMonth() + 1, 0 ).getDay();
const nextDays = 7 - lastDayIndex - 1;
const months =
[ 'January', 'February', 'March', 'April', 'May', 'June'
, 'July', 'August', 'September', 'October', 'November', 'December'
];
document.querySelector(".date h1").innerHTML = months[date.getMonth()];
document.querySelector(".date p").innerHTML = new Date().toDateString();
let days = ''
, count = 0
;
if (lastofweek+7 >= lastDay)
{
for (let x = firstDayIndex; x > 0; x--)
{
days += `<div class="prev-date">${prevLastDay - x + 1}</div>`;
count = count+1;
lastofweek = prevLastDay - x + 1;
lastDay = lastofweek;
}
}
const nxtDay = 7 - count - 1;
if (lastofweek == undefined)
{
for (let i = 1; i <= nxtDay+1; i++)
{
if (i === new Date().getDate() && date.getMonth() === new Date().getMonth())
{
days += `<div class="today">${i}</div>`;
}
else
{
days += `<div>${i}</div>`;
lastDayOfWeek = i;
}
count = count+1;
monthDays.innerHTML = days;
}
}
else
{
if (lastofweek+1 > lastDay)
{
lastofweek = 0;
}
var forCount = 0;
for (let i = lastofweek+1; i <= lastofweek+7; i++)
{
if(lastDay >= i && forCount <= nxtDay)
{
if (i === new Date().getDate() && date.getMonth() === new Date().getMonth())
{
days += `<div class="today">${i}</div>`;
}
else
{
days += `<div>${i}</div>`;
lastDayOfWeek = i;
}
count = count+1;
forCount = forCount + 1;
monthDays.innerHTML = days;
}
}
}
if (count < 7)
{
for (let j = 1; j <= nextDays; j++)
{
days += `<div class="next-date">${j}</div>`;
monthDays.innerHTML = days;
}
}
}
document.querySelector(".prev").addEventListener("click", () =>
{
date.setMonth(date.getMonth());
renderCalendar();
});
const lastDay = new Date( date.getFullYear(), date.getMonth() + 1, 0 ).getDate();
document.querySelector(".next").addEventListener("click", () =>
{
if(lastDayOfWeek+7 > lastDay)
{
date.setMonth(date.getMonth()+1);
renderCalendar(lastDayOfWeek);
}
else
{
date.setMonth(date.getMonth());
renderCalendar(lastDayOfWeek);
}
});
renderCalendar();
* {
margin : 0;
padding : 0;
box-sizing : border-box;
font-family : "Quicksand", sans-serif;
}
html {
font-size : 62.5%;
}
.container {
width : 100%;
height : 100vh;
background-color : #12121f;
color : #eee;
display : flex;
justify-content : center;
align-items : center;
}
.calendar {
width : 45rem;
height : 52rem;
background-color : #222227;
box-shadow : 0 0.5rem 3rem #00000066;
}
.month {
width : 100%;
height : 12rem;
background-color : #167e56;
display : flex;
justify-content : space-between;
align-items : center;
padding : 0 2rem;
text-align : center;
text-shadow : 0 0.3rem 0.5rem #00000080;
}
.month i {
font-size : 2.5rem;
cursor : pointer;
}
.month h1 {
font-size : 3rem;
font-weight : 400;
text-transform : uppercase;
letter-spacing : 0.2rem;
margin-bottom : 1rem;
}
.month p {
font-size : 1.6rem;
}
.weekdays {
width : 100%;
height : 5rem;
padding : 0 0.4rem;
display : flex;
align-items : center;
}
.weekdays div {
font-size : 1.5rem;
font-weight : 400;
letter-spacing : 0.1rem;
width : calc(44.2rem / 7);
display : flex;
justify-content : center;
align-items : center;
text-shadow : 0 0.3rem 0.5rem #00000080;
}
.days {
width : 100%;
display : flex;
flex-wrap : wrap;
padding : 0.2rem;
}
.days div {
font-size : 1.4rem;
margin : 0.3rem;
width : calc(40.2rem / 7);
height : 5rem;
display : flex;
justify-content : center;
align-items : center;
text-shadow : 0 0.3rem 0.5rem #00000080;
transition : background-color 0.2s;
}
.days div:hover:not(.today) {
background-color : #262626;
border : 0.2rem solid #777;
cursor : pointer;
}
.today {
background-color : #167e56;
}
/* --- --- ---
.prev-date,
.next-date {
opacity : 0.5;
}
--- --- --- */
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" >
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght#300;400;500;600;700&display=swap" rel="stylesheet" >
<input type="hidden" name="dates" class="dates" value="<?= $dates ?>" >
<div class="container">
<div class="calendar">
<div class="month">
<i class="fas fa-angle-left prev"></i>
<div class="date">
<h1></h1>
<p></p>
</div>
<i class="fas fa-angle-right next"></i>
</div>
<div class="weekdays">
<div>Sun</div>
<div>Mon</div>
<div>Tue</div>
<div>Wed</div>
<div>Thu</div>
<div>Fri</div>
<div>Sat</div>
</div>
<div class="days"></div>
</div>
</div>
I attempt to create a simple Gantt chart (Table):
I use computed property newTasks() to imitate the getting asynchronously a list of tasks from a Vuex Store but my solution doesn’t work.
Could you help me please.
Not working solution with computed property: https://jsfiddle.net/AlexPilugin/98b0pw24/
new Vue({
el: "#app",
data: {
longMode: false,
columns: 7,
tasks: null
},
watch: {
newTasks(val) {
this.tasks = val;
this.$forceUpdate();
}
},
created() {
this.$nextTick(() => {
this.tasks = this.newTasks;
this.$forceUpdate();
})
},
computed: {
newTasks() {
let tasks = null;
console.log("newTasks-------------");
const self = this;
setTimeout(() => {
if (self.longMode) {
tasks = [{
start: 0,
end: 3
},
{
start: 2,
end: 9
},
{
start: 7,
end: 13
}
];
} else {
tasks = [{
start: 0,
end: 4
},
{
start: 2,
end: 6
}
];
}
console.log("return new tasks:");
console.log(tasks);
return tasks;
}, 2000);
}
},
methods: {
toggle() {
this.longMode = !this.longMode;
this.columns = this.longMode ? 14 : 7;
this.tasks = this.newTasks;
console.log("clicked! longMode: " + this.longMode);
},
getLineStyle(index) {
let rowIndex = 2;
console.log("getLineStyle(" + rowIndex + ")");
console.log(this.$refs);
if (this.tasks && this.tasks.length > 0) {
console.log(this.tasks);
let task = this.tasks[rowIndex];
console.log(task);
let start = task.start;
let end = task.end;
let startRef = 'cell' + start;
let endRef = 'cell' + end;
let startLeft = this.$refs[startRef][0].offsetLeft;
let endLeft = this.$refs[endRef][0].offsetLeft;
let taskWidth = (endLeft - startLeft) + 'px';
let styleObject = {
left: startLeft,
width: taskWidth
};
return styleObject;
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
table {
border-collapse: collapse;
table-layout: auto;
/*fixed;*/
border: 1px solid #012656;
}
.cell {
padding: 5px;
border: 1px solid #012656;
cursor: pointer;
}
td.cell:nth-child(7n-1),
td.cell:nth-child(7n) {
background: #eee;
}
.line {
position: absolute;
top: 4px;
height: 6px;
border-radius: 3px;
background: red;
overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<table class="gantt-table">
<tr #click="toggle">
<td v-for="(cell, colIndex) in columns" :ref="'cell'+colIndex" :key="'col-'+colIndex" class="cell">
{{ colIndex+1 }}
</td>
</tr>
<tr v-show="tasks && tasks.length > 0" v-for="(row, rowIndex) in tasks" :key="'tr-'+rowIndex">
<div style="position: relative;">
<div class="line" :style="getLineStyle(rowIndex)"></div>
</div>
<td v-for="(cell, colIndex) in columns" :key="'row-'+rowIndex+'col-'+colIndex" class="cell">
<div>  </div>
</td>
</tr>
</table>
</div>
Another approach (with method): https://jsfiddle.net/AlexPilugin/qxbd4gcw/
https://jsfiddle.net/AlexPilugin/98b0pw24/3/ - Script is not drawing extra rows based on number of tasks (tasks.length)
and rowIndex in getLineStyle(rowIndex) in undefined! Why?!!
Edit
With Promise
Why watch doesn't work?.
Why both solutions don't work:
<tr v-for="(row, rowIndex) in newTasks" ...>
<tr v-for="(row, rowIndex) in tasks" ..>
Vue.config.productionTip = false;
Vue.config.devtools=false;
new Vue({
el: "#app",
data: {
longMode: false,
columns: 7,
tasks: []
},
created() {
this.tasks = this.newTasks;
},
watch: {
newTasks(tasks) {
console.log("watch: newTasks()-------------");
console.log(tasks);
this.tasks = tasks;
this.$forceUpdate();
}
},
computed: {
newTasks() {
let tasks = null;
if(this.longMode) {
tasks = [
{start: 0, end: 3},
{start: 2, end: 9},
{start: 7, end: 13}
];
} else {
tasks = [
{start: 0, end: 4},
{start: 2, end: 6}
];
}
this.delay(2000).then(() => {
console.log("return new tasks:");
console.log(tasks);
return tasks;
})
}
},
methods: {
toggle() {
this.longMode = !this.longMode;
this.columns = this.longMode ? 14 : 7;
this.tasks = this.newTasks;
console.log("clicked! longMode: " + this.longMode);
},
delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t)
});
},
getLineStyle(index) {
let rowIndex = 2;
console.log("getLineStyle("+rowIndex+")");
console.log(this.$refs);
if(this.tasks && this.tasks.length>0) {
console.log(this.tasks);
let task = this.tasks[rowIndex];
console.log(task);
let start = task.start;
let end = task.end;
let startRef = 'cell'+start;
let endRef = 'cell'+end;
let startLeft = this.$refs[startRef][0].offsetLeft;
let endLeft = this.$refs[endRef][0].offsetLeft;
let taskWidth = (endLeft - startLeft) + 'px';
let styleObject = {left: startLeft, width: taskWidth};
return styleObject;
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
table {
border-collapse: collapse;
table-layout: auto;
/*fixed;*/
border: 1px solid #012656;
}
.cell {
padding: 5px;
border: 1px solid #012656;
cursor: pointer;
}
td.cell:nth-child(7n-1),
td.cell:nth-child(7n) {
background: #eee;
}
.line {
position: absolute;
top: 4px;
height: 6px;
border-radius: 3px;
background: red;
overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<table class="gantt-table">
<tr #click="toggle">
<td
v-for="(cell, colIndex) in columns"
:ref="'cell'+colIndex"
:key="'col-'+colIndex"
class="cell"
>
{{ colIndex+1 }}
</td>
</tr>
<tr
v-show="newTasks && newTasks.length > 0"
v-for="(row, rowIndex) in newTasks"
:key="'tr-'+rowIndex"
>
<!--
<div style="position: relative;">
<div class="line" :style="getLineStyle(rowIndex)"></div>
</div>
-->
<td
v-for="(cell, colIndex) in columns"
:key="'row-'+rowIndex+'col-'+colIndex"
class="cell"
>
<div>  </div>
</td>
</tr>
</table>
</div>
I am trying to count the number of times each value occurs for 'classtext' which is in data.items
However, by adding a function below to do that for each new inputted classtext on button click, I get 0 returned, even if I previously input several 'test' in the classtext field. I am very new in vuejs so obviously I am doing something wrong.
The code looks like this:
<!DOCTYPE html>
<html>
<script src="https://vuejs.org/js/vue.js"></script>
<style>
/* Vue List Item transition */
.list-item-enter-active,
.list-item-leave-active {
transition: opacity 0.3s, -webkit-transform 0.3s;
transition: opacity 0.3s, transform 0.3s;
transition: opacity 0.3s, transform 0.3s, -webkit-transform 0.3s;
-webkit-transform-origin: left center;
transform-origin: left center;
}
.list-item-enter,
.list-item-leave-to {
opacity: 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
/* //////////////////////////////////////// */
/* Basic Styles */
html {
background: #eee;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.list {
background: #FFF;
margin: auto;
padding: 1em 1em 1em;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.2);
}
.list :last-child {
margin-bottom: 0;
}
.list__ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.list__input {
display: flex;
margin-bottom: 0.5em;
}
.list__item {
display: block;
margin-bottom: 0.25em;
}
</style>
</head>
<body>
<div id="example-1" class="list">
<div class="list__input" #keydown.enter="add">
<button v-on:click="count">+</button>
<input v-model="newBeneficiary" placeholder="Add beneficiary" />
<input v-model="newClass" placeholder="Add new task topic" />
<input v-model="newItem" placeholder="Add new task text" />
</div>
<transition-group name="list-item" tag="ul" class="list__ul">
<li class="list__item" v-for="item in items" :key="item">
Timestamp: {{ item.timestamp }} <br />
Beneficiary: {{ item.beneficiarytext }} <br />
Topic: {{ item.classtext }} <br />
Task: {{ item.message }}
</li>
</transition-group>
</div>
</body>
<script>
/**
* Return a timestamp with the format "m/d/yy h:MM:ss TT"
* #type {Date}
*/
function timeStamp() {
var now = new Date();
var date = [ now.getMonth() + 1, now.getDate(), now.getFullYear() ];
var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ];
var suffix = ( time[0] < 12 ) ? "AM" : "PM";
time[0] = ( time[0] < 12 ) ? time[0] : time[0] - 12;
time[0] = time[0] || 12;
for ( var i = 1; i < 3; i++ ) {
if ( time[i] < 10 ) {
time[i] = "0" + time[i];
}
}
return date.join("/") + " " + time.join(":") + " " + suffix;
}
var app = new Vue({
el: '#example-1',
data: {
items: [
/*{ timestamp:'testdate', beneficiarytext: 'TestBeneficiary', classtext: 'TestTopic', message: 'TestMessage' }*/
]
},
methods: {
/* MIGHT BE USED LATER TO DELETE TASKS
remove: function(item){
this.items.splice( this.items.indexOf(item), 1 );
},
*/
add: function(){
this.items.unshift({ timestamp: timeStamp(), beneficiarytext: this.newBeneficiary, classtext: this.newClass, message: this.newItem });
this.newItem = '';
console.log(this.items);
},
count: function() {
var counting = this.items.reduce(function (n, class1) {
return n + (class1.classtext == this.newClass);
}, 0)}
}
})
</script>
</body>
</html>
You didn't bind this to the reducer function. Use
this.items.reduce((n, class1) => { ... })
or
this.items.reduce(function (n, class1) { ... }.bind(this))
See How does the “this” keyword work?.
The compute the counts for each classtext in the array:
this.items.reduce((map, item) => {
map.set(item.classtext, (map.get(item.classtext) || 0) + 1)
return map
}, new Map())
// Returns Map of (classtext, count) pairs:
// {
// apple => 2,
// banana => 6,
// }
I have a Vue Calendar that I'm working on. When a day is clicked, I would like to open a full-width box under the week of the selected day that displays details of the day (Think Google Images layout) I know how to pass data in Vue, but how do I add this details (component, view?) under the row of the current week? (See my CodePen
<div class="calendar">
<div class="header z-depth-2">
<a #click="lastMonth" class="waves-effect waves-light btn"><i class="material-icons left">chevron_left</i>Last Month</a>
<p>{{month}} {{year}}</p>
<a #click="nextMonth" class="waves-effect waves-light btn"><i class="material-icons right">chevron_right</i>Next Month</a>
</div>
<ul class="dates month">
<li class="dow" v-for="dow in days">{{dow}}</li>
<li v-for="blank in firstDayOfMonth" class="day"></li>
<li v-for="date in daysInMonth" #click="openday(date)"
class="day" :class="{'today': date == initialDate && month == initialMonth && year == initialYear}">
<span>{{date}}</span>
</li>
</ul>
</div>
JS
new Vue({
el: '.calendar',
data: {
today: moment(),
dateContext: moment(),
days: ['S', 'M', 'T', 'W', 'T', 'F', 'S']
},
methods:{
nextMonth: function () {
var t = this;
t.dateContext = moment(t.dateContext).add(1, 'month');
},
lastMonth: function () {
var t = this;
t.dateContext = moment(t.dateContext).subtract(1, 'month');
}
},
computed: {
year: function () {
var t = this;
return t.dateContext.format('YYYY');
},
month: function () {
var t = this;
return t.dateContext.format('MMMM');
},
daysInMonth: function () {
var t = this;
return t.dateContext.daysInMonth();
},
currentDate: function () {
var t = this;
return t.dateContext.get('date');
},
firstDayOfMonth: function () {
var t = this;
var firstDay = moment(t.dateContext).subtract((t.currentDate - 1), 'days');
return firstDay.weekday();
},
//Previous Code Above
initialDate: function () {
var t = this;
return t.today.get('date');
},
initialMonth: function () {
var t = this;
return t.today.format('MMMM');
},
initialYear: function () {
var t = this;
return t.today.format('YYYY');
}
}
})
Because you have no concept of a row (you just auto-wrap), you can't really insert a box that takes up a row. What I've done here is insert a div that is positioned absolutely, so that I can make it full width, but it overlays the rows below, rather than shifting them out of the way.
If you rework it to have weeks, you could insert a detail box between weeks.
The basic working, though, is that you set a data item for the currently selected date when you click on a date, and you clear that item to dismiss the detail box (a click in the detail box does it, here). The HTML is controlled by a v-if.
new Vue({
el: '.calendar',
data: {
today: moment(),
dateContext: moment(),
days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
selectedDate: null
},
methods: {
nextMonth: function() {
var t = this;
t.dateContext = moment(t.dateContext).add(1, 'month');
},
lastMonth: function() {
var t = this;
t.dateContext = moment(t.dateContext).subtract(1, 'month');
},
openday(date) {
this.selectedDate = date;
},
dismiss() {
this.selectedDate = null;
}
},
computed: {
year: function() {
var t = this;
return t.dateContext.format('YYYY');
},
month: function() {
var t = this;
return t.dateContext.format('MMMM');
},
daysInMonth: function() {
var t = this;
return t.dateContext.daysInMonth();
},
currentDate: function() {
var t = this;
return t.dateContext.get('date');
},
firstDayOfMonth: function() {
var t = this;
var firstDay = moment(t.dateContext).subtract((t.currentDate - 1), 'days');
return firstDay.weekday();
},
//Previous Code Above
initialDate: function() {
var t = this;
return t.today.get('date');
},
initialMonth: function() {
var t = this;
return t.today.format('MMMM');
},
initialYear: function() {
var t = this;
return t.today.format('YYYY');
}
}
})
*,
*:before,
*:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-size: 1.5em;
font-weight: 100;
color: rgba(255, 255, 255, 1);
background: #222222;
}
.calendar {
transform: translate3d(0, 0, 0);
width: 100vw;
}
.header {
display: flex;
padding: 0 1em;
justify-content: space-between;
align-items: center;
width: 100%;
background-color: #333;
}
.fade-enter {
/*overflow: hidden;*/
opacity: 0;
}
.fade-enter-active {
animation: fadeIn 1s ease-out;
opacity: 1;
}
.month.in.next {
animation: moveFromTopFadeMonth .4s ease-out;
opacity: 1;
}
.month.out.next {
animation: moveToTopFadeMonth .4s ease-in;
opacity: 1;
}
.month.in.prev {
animation: moveFromBottomFadeMonth .4s ease-out;
opacity: 1;
}
.month.out.prev {
animation: moveToBottomFadeMonth .4s ease-in;
opacity: 1;
}
.dates {
display: flex;
flex-wrap: wrap;
}
.day {
width: 14%;
padding: 1em;
text-align: center;
cursor: pointer;
}
.dow {
width: 14%;
text-align: center;
padding: 1em;
color: teal;
font-weight: bold;
}
.detail-panel {
width: 100vw;
background-color: darkred;
color: white;
height: 10rem;
position: absolute;
left: 0;
}
.today {
color: teal;
font-weight: bold;
}
.day-name {
font-size: 1em;
text-transform: uppercase;
margin-bottom: 5px;
color: rgba(255, 255, 255, .5);
letter-spacing: .7px;
}
.day-number {
font-size: 24px;
letter-spacing: 1.5px;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/materialize/0.98.2/css/materialize.min.css" rel="stylesheet" />
<div class="calendar">
<div class="header z-depth-2">
<a #click="lastMonth" class="waves-effect waves-light btn"><i class="material-icons left">chevron_left</i>Last Month</a>
<p>{{month}} {{year}}</p>
<a #click="nextMonth" class="waves-effect waves-light btn"><i class="material-icons right">chevron_right</i>Next Month</a>
</div>
<ul class="dates month">
<li class="dow" v-for="dow in days">{{dow}}</li>
<li v-for="blank in firstDayOfMonth" class="day"></li>
<li v-for="date in daysInMonth" class="day" :class="{'today': date == initialDate && month == initialMonth && year == initialYear}">
<span #click="openday(date)">{{date}}</span>
<div class="detail-panel" v-if="selectedDate === date" #click="dismiss">Hi there I see you selected {{date}}</div>
</li>
</ul>
</div>