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

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;
}
}
})();

Related

How to write forEach method without repeating my code? ShowWeather function javascript

function showForecastWeather(data) {
forecastTitle.forEach((title) => {
if (title.dataset.src === '1') {
const d = new Date(data.list[7].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0,3);
};
if (title.dataset.src === '2') {
const d = new Date(data.list[15].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0, 3)
};
if (title.dataset.src === '3') {
const d = new Date(data.list[23].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0, 3)
};
if (title.dataset.src === '4') {
const d = new Date(data.list[31].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0, 3)
};
if (title.dataset.src === '5') {
const d = new Date(data.list[39].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0, 3)
};
});
How can I write this without repeating my code so much? Like as a function or something?
Is it possible to use index parameter in forEach() method to display API data?
The only thing that changes between the conditions is the index you use to access the list array. As such you can genericise your logic by calculating this value from the src. Something like this:
function showForecastWeather(data) {
forecastTitle.forEach(title => {
const index = (parseInt(this.dataset.src, 10) * 8) - 1;
const d = new Date(data.list[index].dt * 1000);
const dayName = days[d.getDay()];
title.innerText = dayName.slice(0, 3);
});
}

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.

How should I convert the output from minutes to an HH:MM format?

The code is simple, I'm very new to programming. You put in the points you need and the result of the game and the output is the minutes of gameplay needed for the points.
It works, my question is how should I convert the output to be in an HH:MM format? I tried if/else cycles, but it's a lot of work, not to mention it's very primitive and hardcoded. Are for cycles the answer? Should I start from the beginning altogether?
Thank you in advance!
function passPoints(input) {
let gameResult = String(input[0]);
let pointsNeeded = Number(input[1]);
let pointsPerMinute = 0;
if (gameResult == 'w') {
pointsPerMinute = 6;
} else if (gameResult == 'l') {
pointsPerMinute = 4;
}
let minutesOfGameplayNeeded = pointsNeeded / pointsPerMinute;
console.log(minutesOfGameplayNeeded)
}
Here's how I would approach it. Using modulus and dividing by 60 to get the h:m
// as a helper function
const getTimeReadout = m => {
let a = [Math.floor(m / 60), Math.floor(m % 60)]
return a.map(t => ('0' + t).slice(-2)).join(':')
}
Here it is integrated into your code:
function passPoints(input) {
let gameResult = String(input[0]);
let pointsNeeded = Number(input[1]);
let pointsPerMinute = 0;
if (gameResult == 'w') {
pointsPerMinute = 6;
} else if (gameResult == 'l') {
pointsPerMinute = 4;
}
let m = pointsNeeded / pointsPerMinute
let minutesOfGameplayNeeded = [Math.floor(m / 60), Math.floor(m % 60)];
// now it's in an array so we can iterate it below (adding the zero if needed)
minutesOfGameplayNeeded = minutesOfGameplayNeeded.map(t => ('0' + t).slice(-2)).join(':')
console.log(minutesOfGameplayNeeded)
}
passPoints(['w', 427]);
Same thing, but I optimized your code a bit:
function passPoints(input) {
[gameResult, pointsNeeded] = input
let pointsPerMinute = gameResult == 'w' ? 6 : gameResult == 'l' ? 4 : 0;
let m = pointsNeeded / +pointsPerMinute;
return [Math.floor(m / 60), Math.floor(m % 60)].map(t => ('0' + t).slice(-2)).join(':')
}
console.log(passPoints(['w', 427]));

how to make sure that a batch of requests are ready

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..

Problem calculating RSI from the Binance node API

I have written a program in javascript (Node) that is supposed to calculate the RSI using the Binance api.
The only thing is that my program does not calculate the "real" RSI. For example, if i set my period to be 14 days, as the formula says - I get an RSI value equal to ~28 and the real RSI being 38.
If i change the period and set it to 20, i get an RSI pretty close to the real one, with mine being 39 and the real one being 38.
I can't figure it out.what am i doing wrong. Any suggestion?
Here is my code :
const binance = require('node-binance-api')().options({
APIKEY: 'xxx',
APISECRET: 'xxx',
useServerTime: true,
test: true // True = SandboxMode
});
/* VARIABLES */
let listClose = [];
let changeUp = 0;
let changeDown = 0;
let last_closeHigh = 0;
let last_closeLow = 0;
let current_time = Date.now();
let period = 20;
function calculateRSI() {
console.log("Generating RSI");
binance.candlesticks("ETHBTC", "1d", (error, ticks, symbol) => {
for (i = 0; i < ticks.length; i++) {
let last_tick = ticks[i];
let [time, open, high, low, close, volume, closeTime, assetVolume, trades, buyBaseVolume, buyAssetVolume, ignored] = last_tick;
listClose.push(close);
if (i == ticks.length -1 ) {
for (x = 0; x < ticks.length; x++) {
previous_close = (parseFloat(listClose[x-1]));
current_close = (parseFloat(listClose[x]));
// HIGH
if (current_close > previous_close) {
upChange = current_close - previous_close;
changeUp += upChange;
if (x == ticks.length -1) {
last_closeHigh = current_close - previous_close;
}
}
// LOW
if (previous_close > current_close) {
downChange = previous_close - current_close;
changeDown += downChange;
if (x == ticks.length - 1) {
last_closeLow = previous_close - current_close;
}
}
if (x == ticks.length-1) {
AVGHigh = changeUp / period;
AVGLow = changeDown / period;
Upavg = (AVGHigh * (period -1) + last_closeHigh) / (period);
Downavg = (AVGLow * (period -1) + last_closeLow) / (period);
RS = Upavg / Downavg;
RSI = (100 - (100 / (1 + RS)));
console.log(RSI);
return RSI;
}
}
}
}
}, {
limit: period,
endTime: current_time
});
}
calculateRSI();
Sorry for jumping on this late...but the reason for this is using the Sandbox.
Binance Sandbox is awful and should never be used, it gives bad values.

Categories

Resources