how to make sure that a batch of requests are ready - javascript

I need to get via API prices per dates for the following 12 months.
One requirement is that requests cant be over 2 months. So I need to split this in 6 requests.
So I get from current date to +1 month and I iterate 5 times more to get the 10 remaining months, like so:
const getPeriod = (dateIn, dateOut) => {
axios
.post(
Utils.apiUrl,
{
hotelCodes: Utils.hotelId.split(','),
dateIn: dateIn,
dateOut: dateOut,
}
)
.then((response) => {
const calendarPrices = response.data.CalendarPrices
var now = new Date()
for (let d = 0; d < calendarPrices.length; d++) {
const date = new Date(calendarPrices[d].Date)
date.setHours(12, now.getMinutes(), now.getSeconds())
calendarPrices[d].dateObj = date
}
if (Utils.calendarPrices) {
Utils.calendarPrices = Utils.calendarPrices.concat(calendarPrices)
} else {
Utils.calendarPrices = calendarPrices
}
})
.catch((err) => {
console.log(err)
})
}
const getNextMonths = () => {
for (let r = 1; r <= requestsToMake; r++) {
let dateIn = new Date()
dateIn.setMonth(dateIn.getMonth() + 2 * r)
const monthIn =
(dateIn.getMonth() < 9 ? '0' : '') +
(parseInt(dateIn.getMonth(), 10) + 1)
let dateOut = new Date()
dateOut.setMonth(dateOut.getMonth() + 1 + 2 * r)
const monthOut =
(dateOut.getMonth() < 9 ? '0' : '') +
(parseInt(dateOut.getMonth(), 10) + 1)
const lastDayOfMonth = new Date(
dateOut.getFullYear(),
dateOut.getMonth() + 1,
0
)
getPeriod(
`${dateIn.getFullYear()}-${monthIn}-01`,
`${dateOut.getFullYear()}-${monthOut}-${lastDayOfMonth.getDate()}`
)
}
}
// get current month and the next one
axios
.post(
Utils.apiUrl,
{
hotelCodes: Utils.hotelId.split(','),
dateIn: `${dateIn.getFullYear()}-${
(dateIn.getMonth() + 1 < 10 ? '0' : '') +
parseInt(dateIn.getMonth() + 1, 10)
}-${(dateIn.getDate() < 10 ? '0' : '') + dateIn.getDate()}`,
dateOut: `${dateOut.getFullYear()}-${
(dateOut.getMonth() + 1 < 10 ? '0' : '') +
parseInt(dateOut.getMonth() + 1, 10)
}-${
(lastDayOfMonth.getDate() < 10 ? '0' : '') +
lastDayOfMonth.getDate()
}`,
}
)
.then((response) => {
const calendarPrices = response.data.CalendarPrices
var now = new Date()
for (let d = 0; d < calendarPrices.length; d++) {
const date = new Date(calendarPrices[d].Date)
date.setHours(12, now.getMinutes(), now.getSeconds())
calendarPrices[d].dateObj = date
}
if (Utils.calendarPrices) {
Utils.calendarPrices = Utils.calendarPrices.concat(
calendarPrices
)
} else {
Utils.calendarPrices = calendarPrices
}
datepicker = new HotelDatepicker(input, options)
// get 10 more months
getNextMonths()
})
The problem i'm having is that those are async calls when the calendar is ready only the first request is complete
How can i make sure all dates have been recived before I init the calendar?
I'm thinking in making a recursive function but i don't know how to handle the callbacks..

Related

How to create a stopwatch lap time function in Javascript

I am trying to create a stopwatch app that displays lap times. Currently I have it displaying the time when the lap button is clicked. However, I want to display the difference between time a and time b, time b and time c and so forth.
Can anyone suggest a way to do this?
I have looked at different responses on various blogs and stack overflow but haven't found one I fully understood. So I didn't want to just copy code.
I have included a snippet of the code I believe to be relative to the problem.
const timer = document.getElementById("stopwatch");
const startButton = document.getElementById("startButton");
let lapNumber = 0;
let [hour, min, sec, centisecond] = [0, 0, 0, 0];
let stopTime = true;
let [lapHour, lapMin, lapSec, lapCentiSec] = [0, 0, 0, 0];
function startTimer() {
if (startButton.innerText === "Start") {
startButton.innerText = "Stop";
stopTime = false;
timerCycle();
} else if (startButton.innerText === "Stop") {
startButton.innerText = "Start";
stopTime = true;
}
}
function timerCycle() {
if (stopTime === false) {
// Set timings to numbers
centisecond = parseInt(centisecond);
sec = parseInt(sec);
min = parseInt(min);
hour = parseInt(hour);
centisecond = centisecond + 1;
if (centisecond == 100) {
sec = sec + 1;
centisecond = 0;
}
if (sec === 60) {
min = min + 1;
sec = 0;
}
if (min === 60) {
hour = hour + 1;
min = 0;
sec = 0;
}
if (centisecond < 10 || centisecond === 0) {
centisecond = "0" + centisecond;
}
if (sec < 10 || sec === 0) {
sec = "0" + sec;
}
if (min < 10 || min === 0) {
min = "0" + min;
}
if (hour < 10 || hour === 0) {
hour = "0" + hour;
}
timer.innerHTML = `${hour}:${min}:${sec}:${centisecond}`;
setTimeout("timerCycle()", 10);
}
}
function lapTime() {
lapNumber++;
const lapTimes = `${lapNumber}: ${timer.innerHTML}`;
setLocalStorage("laps", lapTimes);
}
function setLocalStorage(key, data) {
const lapTimes = JSON.parse(localStorage.getItem(key)) || [];
lapTimes.push(data);
localStorage.setItem(key, JSON.stringify(lapTimes));
displayLaps(lapTimes);
}
function displayLaps(lapTimes) {
const lapContainer = document.querySelector("#lapList");
const laps = document.createElement("li");
laps.className = "lap-time";
if (timer.innerHTML === "00:00:00:00") {
laps.innerHTML = "Please press start.";
lapContainer.appendChild(laps);
return;
} else {
const pressStart = Array.from(document.getElementsByClassName("lap-time"));
pressStart.forEach((text) => {
if (text.innerHTML === "Please press start.") {
text.remove();
}
});
}
lapTimes.forEach((lapTime) => {
laps.innerHTML = lapTime;
});
lapContainer.appendChild(laps);
}
Don't bother with all those centisecsonds etc.
Just get the number of millsecs of the current time when 'Start' is clicked
let d = new Date();
let start_ms = d.valueOf();
then do the same again when 'Stop' is clicked, and subtract the values to find the milisecs elapsed. Then convert to readable hours, mins secs for the user.

Starting time in the program is not working properly

I have a function returnTimesInBetween. It's taking two values (start, end) as parameters and returns the time array by splitting in the 30 minutes of the time frame. the problem is when the start time is ending with 30 minutes like "12:30,11:30,15:30" it's not taking that value in the time frame and when the start time is like 11:00, 12:00, etc it's working fine.
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
if (startM == 30)
startH++;
for (var i = startH ; i < endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00")
timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30");
}
if (endM == 00)
timesInBetween.push(endH + ":30");
if (endM == 30)
timesInBetween.push(endH + ":30")
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));
console output are
[]0: "12:00"
1: "12:30"
2: "13:00"
3: "13:30"
4: "14:00"
5: "14:30"
6: "15:30"
length: 7[[Prototype]]: Array(0)
[]0: "18:00"
1: "18:30"
2: "19:00"
3: "19:30"
4: "20:00"
5: "20:30"
6: "21:30"
length: 7[[Prototype]]: Array(0)
How can i add the starting time even if it's ending with 30 minute hand.
You need a condition just for the first iteration, when starM is not 30.
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end) {
var timesInBetween = [];
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
for (var i = startH; i < endH; i++) {
// Add a condition here for the first iteration only
if (i === startH && startM !== 30) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
}
timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30");
}
if (endM == 0) timesInBetween.push(endH + ":30");
if (endM == 30) timesInBetween.push(endH + ":30");
return timesInBetween; // Was missing ;)
}
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));
Another approach I like when working with time, instead of working with hour, minute (and second) separately, crunch them into a single number (in this case minutes) and do all calculation with the number. Only convert back to human-readable format when finish computing. This way you avoid making mistake when changing one component and forget the other. This applies to other non-base 10 system as well.
function returnTimesInBetween(start, end)
{
let result = [];
const s = start.split(":").reduce((a,c) => a * 60 + Number(c));
const e = end.split(":").reduce((a,c) => a * 60 + Number(c));
const mod = (s % 30);
for(let i = s + (mod ? 30 - mod : 0) ; i <= e; i += 30)
{
const h = Math.floor(i/60);
const m = i % 60;
result.push(`0${h}`.slice(-2) + ":" + `0${m}`.slice(-2) );
}
return result;
}
console.log(returnTimesInBetween("11:00","15:29"));
console.log(returnTimesInBetween("11:00","15:30"));
console.log(returnTimesInBetween("11:29","15:30"));
console.log(returnTimesInBetween("11:30","15:30"));
console.log(returnTimesInBetween("11:31","15:30"));
Just for fun I wanted to see if I could produce a compact method to achieve this. This method uses a lot of shorthand syntax and could be difficult to follow. However, the premise is to convert the times into decimals, ie: 11:30 becomes 11.5, 21:00 becomes 21. The + preceding the h and m, in the reduce function, is shorthand to convert the string to a number.
We can then define an array of a given size by deducting the endtime-decimal from our starttime-decimal and multiplying by 2. Then we fill the array with incrementing 0.5 decimal numbers ie. 11.5, 12, 12.5, 13...
Finally map the array to convert back to a time-string format. Again this uses techniques like the bit operator | which return a whole number and the modulo operator (also called remainder) % which returns a remainder, in this case 0 or 0.5.
let splitTime = (start, end) => {
let shm = start.split(":").reduce((h,m) => +h + (+m/60)) - 0.5,
ehm = end.split(":").reduce((h,m) => +h + (+m/60));
return Array((ehm - shm) * 2).fill().map(_ => shm+=0.5)
.map(hm => (hm | 0) + ':' + (hm % 1 ? "30" : "00"));
}
console.log(splitTime("11:30", "15:30"));
console.log(splitTime("18:00", "21:00"));
console.log(splitTime("9:00", "23:30"));
console.log(splitTime("10:30", "14:00"));
Your condition on the for loop should be i <= endH; and you can use th if condition according to your need of the output.
for (var i = startH ; i <= endH; i++) {
From what i understand your expected output is:
("11:30", "15:30") => ["11:00","11:30","12:00","12:30","13:00","13:30","14:00","14:30","15:00","15:30"]
("18:00", "21:30") => [ "18:00","18:30","19:00","19:30","20:00","20:30","21:00","21:30" ]
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
for (var i = startH ; i <= endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
(i == endH && endM == 30) ? timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30") : '';
}
return timesInBetween;
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:00"));
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));
Or
if you are expecting somthing like this, just add the if condition:
["11:30","12:00","12:30","13:00","13:30","14:00","14:30","15:00","15:30"]
["18:00","18:30","19:00","19:30","20:00","20:30","21:00","21:30"]
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
if (startM == 30) {
timesInBetween.push(startH < 10 ? "0" + startH + ":30" : startH + ":30");
startH++;
}
for (var i = startH ; i <= endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
(i == endH && endM == 30) ? timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30") : '';
}
return timesInBetween;
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:00"));
console.log(returnTimesInBetween("18:00", "21:30"));

Unable to exit the function after 'window.alert' in Angular9

I am trying to calculate time difference and if time difference is greater than 20 mins, I want to display an alert message and then exit.
I don't intend to loop through all the rows and want to exit the function after finding out the first host which has minutes < 20.
this.dataSource.filteredData.forEach(
async row => {
this.selection.select(row);
// const host = row.hostName.substring(0, row.hostName.indexOf('.'));
const host = 'abc';
const prevData = await this.myService.getData(host);
const timeDiff = Math.abs(new Date().getTime() - new Date(prevData[0].dateAt).getTime());
const minutes = Math.floor((timeDiff / 1000) / 60);
if (minutes < 20) {
window.alert('Please check after ' + (20 - minutes) + ' minutes.');
return false;
}
});
I am trying to exit the function using return false but it is still looping through all the rows.
Updated code without foreach:
const f = (async row => {
const host = 'abc';
const prevData = this.myService.getData(host);
const timeDiff = Math.abs(new Date().getTime() - new Date(prevData[0].dateAt).getTime());
const minutes = Math.floor((timeDiff / 1000) / 60);
return minutes;
});
(async () => {
for (let i = 0; i < this.dataSource.filteredData.length; i++) {
const mins = await f(this.dataSource.filteredData[i]);
if (mins < 200) {
window.alert('Please retry after ' + (200 - mins) + ' minutes.');
break;
}
}
})();
In the above code, this.myService.getData(host) is returning null
Here is a minimally-viable representation of how the control should be programmed:
let rows = [1, 2, 3];
let f = (async row => {
return row === "2";
});
(async () => {
for (let i = 0; i < rows.length; i++) {
let result = await f(rows[i]);
console.log(result);
if (!result) {
break;
}
}
})();

How do i call a javascript function to execute after another script ends

I am trying to call function sumWH after the completion of the function sumMon1. Both functions get the text from labels, sum up their values, and update a counter label. The code that I have attempted to use to call sumHW after sumMon1 is below and does not work.
$.when(sumMon1()).done(function () {
sumWH();
});
the sum functions look like this:
<script>
$.when(sumMon1()).done(function () {
sumWH();
});
function sumWH() {
alert(event.target);
//Get Friday AM Out Value
var a = parseInt($('[id$="lblWeek1FridayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN Value
var b = parseInt($('[id$="lblWeek2FridayTotalHrs"]').val(), 10) || 0;
//Get Friday PM Out Value
var c = parseInt($('[id$="lblWeek1SaturdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN VALUE
var d = parseInt($('[id$="lblWeek2SaturdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM Out Value
var e = parseInt($('[id$="lblWeek1SundayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN Value
var f = parseInt($('[id$="lblWeek2SundayTotalHrs"]').val(), 10) || 0;
//Get Friday PM Out Value
var g = parseFloat($('[id$="lblWeek1MondayTotalHrs"]').val(), 10);
//Get Friday AM IN VALUE
var h = parseInt($('[id$="lblWeek2MondayTotalHrs"]').val(), 10) || 0;
//Get Friday AM Out Value
var i = parseInt($('[id$="lblWeek1TuesdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN Value
var j = parseInt($('[id$="lblWeek2TuesdayTotalHrs"]').val(), 10) || 0;
//Get Friday PM Out Value
var k = parseInt($('[id$="lblWeek2WednesdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN VALUE
var l = parseInt($('[id$="lblWeek1WednesdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM Out Value
var m = parseInt($('[id$="lblWeek2ThursdayTotalHrs"]').val(), 10) || 0;
//Get Friday AM IN Value
var n = parseInt($('[id$="lblWeek1ThursdayTotalHrs"]').val(), 10) || 0;
var result = a + b + c + d + e + f + g + h + i + j + k + l + m + n;
if (result > 0 && result < 81 && !isNaN(result)) {
$('[id$="txtTotalHours"]').html(result);
} else if (result == 0) {
$('[id$="txtTotalHours"]').html(0);
} else if (isNaN(result)) {
$('[id$="txtTotalHours"]').html(result);
}
}
</script>
<script>
$(document).ready(function () {
sumMon1();
$('[id$="txtWeek1MondayPM_OUT"], [id$="txtWeek1MondayAM_OUT"]').on("blur", function () {
sumMon1();
});
});
function sumMon1() {
//Get Monday AM Out Value
var Out2Dec = $('[id$="txtWeek1MondayAM_OUT"]').val();
//split dec and whole AM OUT
var OutAmDec = Out2Dec % 1;
var OutAMWhole = Math.floor(Out2Dec);
if (OutAMWhole < 12 && OutAMWhole != 0 && !isNaN(OutAMWhole)) {
OutAMWhole += 12;
}
//Get Monday AM IN Value
var In2Dec = $('[id$="txtWeek1MondayAM_IN"]').val();
//split dec and whole AM IN
var InAmDec = In2Dec % 1;
var InAmWhole = Math.floor(In2Dec);
//Get Monday PM Out Value
var Out1Dec = $('[id$="txtWeek1MondayPM_OUT"]').val();
//split dec and whole PM OUT
var OutPmDec = Out1Dec % 1;
var OutPMWhole = Math.floor(Out1Dec);
if (OutAMWhole < 12 && OutAMWhole != 0 && !isNaN(OutAMWhole)) {
OutPMWhole += 12;
}
//Get Monday AM IN VALUE
var In1Dec = $('[id$="txtWeek1MondayPM_IN"]').val();
//split dec and whole PM IN
var InPmDec = In1Dec % 1;
var InPMWhole = Math.floor(In1Dec);
//calculate times
var InAmVal = (InAmWhole * 60) + (InAmDec * 100);
var OutAmVal = (OutAMWhole * 60) + (OutAmDec * 100);
var InPmVal = (InPMWhole * 60) + (InPmDec * 100);
var OutPmVal = (OutPMWhole * 60) + (OutPmDec * 100);
var Difference = (OutAmVal - InAmVal) + (OutPmVal - InPmVal);
var result = Difference / 60;
//display result
if (result > 0 && !isNaN(result)) {
$('[id$="lblWeek1MondayTotalHrs"]').html(result.toFixed(2));
} else {
var value2 = (result.toFixed(2) * -1);
$('[id$="lblWeek1MondayTotalHrs"]').html(value2);
}
}
</script>
The sum functions are located in separate script tags. sumMon1 is set to go on blur from a series of textboxes.
Is this there a way to make this function work or is there a better way to accomplish this?
jQuery.when is for async functions.
async is something like setInterval or jQuery.ajax.
And except async stuff, JavaScript (Or almost any other languages as well) run codes from top to the bottom sequentially.
Your code is not using asynchronous things. so simply do
sumMon();
sumWH();

Add two timestamps of format "HH+:MM:SS"

So basically i have two strings of timestamps which i want to add:
a = "00:10:12";
aParts = a.split(/:/);
b = "00:30:34";
bParts = b.split(/:/);
time1 = 3600000 * parseInt(aParts[0]) + 60000 * parseInt(aParts[1]) + 1000 * parseInt(aParts[2]);
time2 = 3600000 * parseInt(bParts[0]) + 60000 * parseInt(bParts[1]) + 1000 * parseInt(bParts[2]);
dateTime = time1 + time2;
hours = parseInt(dateTime/3600000);
dateTime = parseInt(dateTime%3600000);
minutes = parseInt(dateTime/60000);
dateTime = parseInt(dateTime%60000);
seconds = parseInt(dateTime/1000);
newTime = addLeadingZeros(hours,2) + ':' + addLeadingZeros(minutes,2) + ':' + addLeadingZeros(seconds,2);
// returns correct "00:40:46"
function addLeadingZeros (n, length){
var str = (n > 0 ? n : -n) + "";
var zeros = "";
for (var i = length - str.length; i > 0; i--)
zeros += "0";
zeros += str;
return n >= 0 ? zeros : "-" + zeros;
}
While writing this question i managed to come up with the above code :-) that works somehow - is that a proper way of adding two string timestamps or is there a better approach?
Forgot to mention - i did try converting the two strings into Date objects and using .getTime() adding the two datetimes - but that gives me a wrong time in the date.
There is nothing notably wrong with your code, but be sure to set the radix when using parseInt
radix
An integer that represents the radix of the value to parse. Always
specify this parameter to eliminate reader confusion
and to guarantee predictable behavior. Different implementations
produce different results when a radix is not specified.
There is no standard method for performing the task that you have described.
Here is an example that I have used in the past.
Javascript
/*jslint maxerr: 50, indent: 4, browser: true, devel: true */
(function () {
"use strict";
function zeroPad(num) {
var str = num.toString();
if (num < 2) {
str = "0" + str;
}
return str;
}
function addTimes() {
if (!arguments.length) {
throw new SyntaxError("No arguments provided.");
}
var total = {
hours: 0,
minutes: 0,
seconds: 0
},
argIndex,
argLength,
time,
parts,
part,
partIndex,
temp;
for (argIndex = 0, argLength = arguments.length; argIndex < argLength; argIndex += 1) {
time = arguments[argIndex];
if (typeof time !== "string") {
throw new TypeError("Argument must be a string.");
}
parts = time.split(":");
if (parts.length !== 3) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
for (partIndex = 0; partIndex < 3; partIndex += 1) {
part = parts[partIndex];
if (partIndex < 2) {
if (part === "" || !/^\d*$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseInt(part, 10);
} else {
if (part === "" || !/^\d*\.?\d+$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseFloat(part);
}
}
temp = (parts[2] + total.seconds);
total.seconds = temp % 60;
temp = (parts[1] + total.minutes) + (temp - total.seconds) / 60;
total.minutes = temp % 60;
total.hours = (parts[0] + total.hours) + (temp - total.minutes) / 60;
}
return zeroPad(total.hours) + ":" + zeroPad(total.minutes) + ":" + zeroPad(total.seconds);
}
var a = "00:10:12",
b = "00:30:34",
c = "10:40:40";
console.log(addTimes(a, b, c));
}());
Output
11:21:26
On jsfiddle

Categories

Resources