function does not make it past else if - javascript

Why is my pastPres function not working? It is supposed to change the color for a time block in a calendar depending on whether that block is in the past present or future.
$(document).ready(function () {
$(".saveBtn").on("click", function () {
var description = $(this).siblings(".description").val();
var time = $(this).parent().attr("id")
localStorage.setItem(time, description)
})
function pastPres() {
var blockTime = moment().hour()
$(".time-block").each(function () {
var time = $(this).attr("id")
if (time < blockTime) {
$(this).addClass("past")
} else if(time > blockTime) {
$(this).removeClass("past")
$(this).addClass("future")
} else {
$(this).removeClass("future")
$(this).addClass("present")
}
})
}
pastPres()
var interval = setInterval(pastPres, 15000)
$("#9am .description").val(localStorage.getItem("9am"))
$("#10am .description").val(localStorage.getItem("10am"))
$("#11am .description").val(localStorage.getItem("11am"))
$("#12pm .description").val(localStorage.getItem("12pm"))
$("#1pm .description").val(localStorage.getItem("1pm"))
$("#2pm .description").val(localStorage.getItem("2pm"))
$("#3pm .description").val(localStorage.getItem("3pm"))
$("#4pm .description").val(localStorage.getItem("4pm"))
$("#5pm .description").val(localStorage.getItem("5pm"))
$("#currentDay").text(moment().format("MMMM DD, YYYY"))
})

You are comparing strings. You need to compare time values instead. Since you are using moment you can invoke a new moment instance for the time and let it handle parsing to military time:
function pastPres() {
var blockTime = moment().hour();
$(".time-block").each(function () {
var time = moment($(this).attr("id"), ["hA"]).hour()
if (time < blockTime) {
$(this).addClass("past")
} else if(time > blockTime) {
$(this).removeClass("past")
$(this).addClass("future")
} else {
$(this).removeClass("future")
$(this).addClass("present")
}
})
}

Assuming your .time-block elements are the same as #9am, #10am, etc, it appears you're trying to compare a string to a number like
'9am' < 10
which as far as JavaScript is concerned, is false.
I suggest you add some better data to your elements like
<div id="9pm" data-hour="21" class="time-block">
and use
const time = $(this).data('hour')

Related

How to start a timer without page refresh (Rails/JavaScript)?

I have a model named 'Deal' which has start_at and end_at attributes. I have implemented a countdown timer using hotwire/stimulus JS.
When the deal starts (start date is in the past, end date is in the future), the countdown timer displaying time left to deal will be shown. e.g Time left to deal: 2 hours, 4 minutes, 30 seconds and so on. It will decrement by 1 second.
If the deal has not yet started (start date is in the future), the page will show "Deal is going to start on #{datetime}".
However, the user needs to refresh the page they are currently on to see a timer if the deal has started in the meantime (i.e. transitioning from "Deal is going to start on #{datetime}" to a countdown timer). I am wondering what's the best way to start the timer without refreshing the page. Thanks.
The way to manage a 'timer' that runs some function every X milliseconds is via the browser's setInterval function.
This function can be used like this - const intervalID = setInterval(myCallback, 500); - where myCallback is the function that will attempt to run every 500ms.
The timer can be 'cancelled' by calling clearInterval and giving it the interval ID that is created as the result of setInterval.
Example HTML
Here we have a basic HTMl structure where we set our controller timer and set the from/to times along with targets that hold the messages based on three states.
These three states are 'before', 'during' (when the current time is between the two times) and 'after'.
<section class="prose m-5">
<div
data-controller="timer"
data-timer-from-value="2022-03-08T10:41:32.111Z"
data-timer-to-value="2022-03-09T11:10:32.111Z"
>
<div style="display: none" data-timer-target="before">
Deal will start on <time data-timer-target="fromTime"></time>
</div>
<div style="display: none" data-timer-target="during">
Deal is active <time data-timer-target="toTimeRelative"></time>
</div>
<div style="display: none" data-timer-target="after">
Deal ended on <time data-timer-target="toTime"></time>
</div>
</div>
</section>
Example Stimulus Controller
This timerController accepts the to and from times as strings (ISO strings are best to use, and remember the nuances of time-zones can be complex).
When the controller connects we do three things; 1. set up a timer to run this.update every X milliseconds and put the timer ID on the class for clearing later as this._timer. 2. Set the time values (the inner time labels for messaging). 3. Run the this.update method the initial time.
this.getTimeData parses the from/to datetime strings and does some basic validation, it also returns these date objects along with a status string which will be one of BEFORE/DURING/AFTER.
this.update - this shows/hides the relevant message parts based on the resolved status.
import { Controller } from '#hotwired/stimulus';
const BEFORE = 'BEFORE';
const DURING = 'DURING';
const AFTER = 'AFTER';
export default class extends Controller {
static values = {
interval: { default: 500, type: Number },
locale: { default: 'en-GB', type: String },
from: String,
to: String,
};
static targets = [
'before',
'during',
'after',
'fromTime',
'toTime',
'toTimeRelative',
];
connect() {
this._timer = setInterval(() => {
this.update();
}, this.intervalValue);
this.setTimeValues();
this.update();
}
getTimeData() {
const from = this.hasFromValue && new Date(this.fromValue);
const to = this.hasToValue && new Date(this.toValue);
if (!from || !to) return;
if (from > to) {
throw new Error('From time must be after to time.');
}
const now = new Date();
const status = (() => {
if (now < from) return BEFORE;
if (now >= from && now <= to) return DURING;
return AFTER;
})();
return { from, to, now, status };
}
setTimeValues() {
const { from, to, now } = this.getTimeData();
const locale = this.localeValue;
const formatter = new Intl.DateTimeFormat(locale, {
dateStyle: 'short',
timeStyle: 'short',
});
this.fromTimeTargets.forEach((element) => {
element.setAttribute('datetime', from);
element.innerText = formatter.format(from);
});
this.toTimeTargets.forEach((element) => {
element.setAttribute('datetime', to);
element.innerText = formatter.format(to);
});
const relativeFormatter = new Intl.RelativeTimeFormat(locale, {
numeric: 'auto',
});
this.toTimeRelativeTargets.forEach((element) => {
element.setAttribute('datetime', to);
element.innerText = relativeFormatter.format(
Math.round((to - now) / 1000),
'seconds'
);
});
}
update() {
const { status } = this.getTimeData();
[
[BEFORE, this.beforeTarget],
[DURING, this.duringTarget],
[AFTER, this.afterTarget],
].forEach(([key, element]) => {
if (key === status) {
element.style.removeProperty('display');
} else {
element.style.setProperty('display', 'none');
}
});
this.setTimeValues();
if (status === AFTER) {
this.stopTimer();
}
}
stopTimer() {
const timer = this._timer;
if (!timer) return;
clearInterval(timer);
}
disconnect() {
// ensure we clean up so the timer is not running if the element gets removed
this.stopTimer();
}
}

removing cookies using javascript is not done immediatly

I am currently working with a javascript that is supposed to remove some unwanted cookies, but for some reason aren't they removed when told to?..
only after certain amount of times trying to remove them, they seem to be removed.. some sort of delayed effect?
here is the code:
const name = 'test_u';
const name1 = 'test_te_s';
function eraseCookie(name) {
document.cookie = name+'=; Max-Age=-99999999;';
}
function removeCookies(cookieA, cookieB) {
setInterval(function() {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB))
{
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
},10000);
}
removeCookies(name, name1);
example from console log output:
1555420706478
1555420716477
1555420726487
1555420736487
1555420746497
1555420756487
It runs 6 times before its removed? but why though?
why aren't they removed immediately?
Because you have setInterval which means that that code will be run after some time that you provide, and keep repeating it by that interval. So just remove that setInterval:
function removeCookies(cookieA, cookieB) {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB)) {
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
}
And if you want to keep repeating it try this one:
removeCookies(name, name1);
setInterval(() => {
removeCookies(name, name1);
}, 10000);
or
function removeCookies(cookieA, cookieB) {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB)) {
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
setInterval(() => {
removeCookies()
}, 10000);
}
removeCookies(name, name1);
so it will first call removeCookies, and then it will keep repeating.

how can I add the ticking clock to my div in an existing code?

It's actually a follow up to this question I want to display elements from json based on their time and duration and interval is interupted by settimeout - I accepted the answer there made by #Daniel Flint - his code is quite clear and can be found here http://jsfiddle.net/nauzilus/rqctam5r/
However, there's one more thing that I wanted to add - a simple div <div id="time"></div> that would contain a new date time object initialized during opening the page and then it being incremented every second just to show the current time constantly. I thought about writing there a javascript:
var actualTime = new Date(substractedDate); // taken from the server
function updateTimeBasedOnServer(timestamp) {
var calculatedTime = moment(timestamp);
var dateString = calculatedTime.format('h:mm:ss A');
$('#time').html(dateString + ", ");
};
var timestamp = actualTime.getTime();
updateTimeBasedOnServer(timestamp);
setInterval(function () {
timestamp += 1000; // Increment the timestamp at every call.
updateTimeBasedOnServer(timestamp);
}, 1000);
(I provide the time of the server as a timestamp there).
I just noticed that there is a slight mismatch between displaying the time in my div and between the text appearing on the screen, possibly because I increment both of the values in two different places.
So my question is - how can I "merge" #Daniel Flint's code with mine and increment both values only in one place?
One thing that jumps out here:
timestamp += 1000;
setTimeout/setInterval aren't guaranteed to run at precisely the delay you've entered. Run this in your browsers console:
var last = Date.now(),
time = function() {
var now = Date.now();
console.log(now - last);
last = now;
},
id = setInterval(time, 1000);
On my Mac at home (Chrome/FireFox) it was anywhere from 990 to 1015. Windows machine at work is a bit better (995-1002), but IE was getting up to 1020. It's not a huge difference, but it's not nothing.
So code needs to be able to handle not running exactly every 1000ms. That's why I was running the timer at 500ms intervals, and checking if the start time was less-than-equal to the current time.
I've rejigged the demo to show the time and message in sync:
(function() {
var messages = [];
var time = document.getElementById("current-time");
var display = document.getElementById("message");
function check() {
showMessage(currentMessage());
showTime();
}
function currentMessage() {
var message = null;
if (messages.length) {
var now = toTheSecond(new Date());
var start = toTheSecond(new Date(messages[0].start_time));
var end = toTheSecond(new Date(start.getTime() + ( messages[0].text_duration * 1000 )));
if (start <= now) {
if (end <= now) {
// done with the current message...
messages = messages.slice(1);
// ...but check if there's another one ready to go right now
message = currentMessage();
}
else {
message = messages[0];
}
}
}
return message;
}
function toTheSecond(date) {
date.setMilliseconds(0);
return date;
}
function showMessage(message) {
if (message) {
display.textContent = message.text_content;
}
else {
display.textContent = "no messages";
}
}
function showTime() {
time.textContent = new Date().toLocaleString()
}
function getMessages() {
setTimeout(function() {
var now = new Date();
messages.push(
{"text_content":"aaaaa","text_duration":5,"start_time": new Date(now.getTime() + 3000).toISOString()},
{"text_content":"aawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 10000).toISOString()},
{"text_content":"bbaawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 15000).toISOString()}
);
}, 1000);
}
setInterval(check, 500);
getMessages();
})();
<span id="current-time"></span> <span id="message">Hello there!</span>
(Putting the code here as well because I recall SO want code in the answers so it's controlled, but there's a demo here: http://jsfiddle.net/nauzilus/ymp0615g/).
This probably isn't as efficient as it could be; the message text is being set every iteration which might cause repaints/reflow. But then again setting the time stamp is going to do that anyway, so meh :)

understanding javascript code with callbacks

Below you see a part of the server-side code of the twich.me node.js chat:
exports.channel = function(MESSAGE_BACKLOG, MESSAGE_TRUNCATE) {
return (function() {
var messages = [],
callbacks = [];
return {
appendMessage : function (nick, room, type, text) {
//truncate message if necessary
if (type == 'msg' && text.length > MESSAGE_TRUNCATE) {
text = text.substr(0, MESSAGE_TRUNCATE) + "... (trunc.)";
}
//message
var m = {
nick: nick,
type: type, // "msg", "join", "part"
text: text,
room: room,
timestamp: (new Date()).getTime()
};
//output to console
// mlog(m);
//push msg on message stack
messages.push( m );
//???
while (callbacks.length > 0) {
callbacks.shift().callback([m]);
}
//old messages get pushed out of message stack
while (messages.length > MESSAGE_BACKLOG) {
messages.shift();
}
},
query : function (room, since, callback) {
var matching = [];
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
if (message.timestamp > since && room == message.room) {
matching.push(message)
}
}
//???
if (matching.length != 0) {
callback(matching);
}
else {
callbacks.push({ timestamp: new Date(), callback: callback });
}
},
//run initially when script starts
init : function() {
// clear old callbacks older than 25 seconds (lowered from 30 seconds to get round rmit proxy server's 30sec timeout
setInterval(function () {
var now = new Date();
while (callbacks.length > 0 && now - callbacks[0].timestamp > 25*1000) {
callbacks.shift().callback([]);
}
}, 3000);
return "hi";
}
}
}());
}
The code is responsible for storing and retrieving chat messages from one of the chat rooms.
I am not a javascript programmer. My background is with PHP where everything is procedural. I want to solve this with memcached instead. But first I need to understand what exactly is going on. I have added extra comments. What I don't understand is all the stuff with the callbacks. Could you help me understand what the callbacks are doing?
I don't really understand what you want but here's what going on:
while (callbacks.length > 0) {
callbacks.shift().callback([m]);
}
while the amount of objects in the array callbacks is greater than 0,
callbacks.shift() function will apparently return an object with a property called callback which is a function. and it's calling that function with an array that has the variable m in it.
if (matching.length != 0) {
callback(matching);
}
else {
callbacks.push({ timestamp: new Date(), callback: callback });
}
}
if the amount of objects in the array matching is not 0, call the function callback or if it does, cal the function callback.push with an object.

javascript // what is going on here?

Im looking at a javascript file trying to figure out a timer issue, but im lost as to what exactly is happening here. Could someone break down this code into bite sizes and explain what is going on?
Timer=0;
function countdown(auctionid) {
var auctions;
var divs;
Timer=Timer+1;
if((Timer%10=="0")||(Timer=="1")) {
$.get("current.php", {
id:auctionid
}, function(data) {
auctions=data.split("||");
for(n=0;n<=auctions.length;n++) {
if(auctions[n] != undefined) {
divis=auctions[n].split("##");
$('#futu'+divis[0]).html(divis[1]);
}
}
});
}
var cauctionid="auctionid";
var tauctions=auctionid.split("|");
for(i=0;i<=tauctions.length;i++) {
if(tauctions[i] != undefined) {
var dd=$('#futu'+tauctions[i]).text();
var cdd=dd-1;
$('#futu'+tauctions[i]).html(cdd);
dd=dd*1000;
dday=Math.floor(dd/(60*60*1000*24)*1)
dhour=Math.floor(dd/(60*60*1000)*1)
dmin=Math.floor((dd%(60*60*1000))/(60*1000)*1)
dsec=Math.floor(((dd%(60*60*1000))%(60*1000))/1000*1)
if(dday==0 && dhour==0 && dmin==0 && dsec==0) {
$('#Bid'+tauctions[i]).html("SOLD");
//return
}
if(dhour <=9) {
dhour = "0"+dhour;
}
if(dmin <=9) {
dmin = "0"+dmin;
}
if(dsec <=9) {
dsec = "0"+dsec;
}
if(dd>=1000) {
var valll=dhour+":"+dmin+":"+dsec;
}
if(dd<1000) {
var valll="00:00:00";
}
$('#Bid'+tauctions[i]).html(valll);
}
}
refreshID = setTimeout("countdown('"+auctionid+"')", 1000);
}
Every second, this script will update the time left for each of the "auctions" on the page. The second argument to setTimeout() is the time to wait in milliseconds, thus 1000 = 1 second.
Also, on the 1st second, and every 10s afterwards, it will make an AJAX call to retrieve a set of auctions in double-pipe (||) delimited string format. It then updates the corresponding auctions on the page with the data from the server.

Categories