I cannot read the title attribute from the received variable, but as you see the collection is not undefined, and the title attribute also not undefined.
The error saying its undefined.
var received = document.getElementsByClassName("_2her");
if (received[0].title == "Delivered") {
chColorsForDelivered();
}
Your script started before DOM ready, If you are using html5, then use async with you script.
If you only want to check that first element (and make sure it's there after the page loads), I usually use this method:
window.onload = function() {
var received = document.getElementsByClassName("_2her")[0];
if (received.title == "Delivered") {
chColorsForDelivered();
}
}
You could also use querySelector to get the first occurrence of the class, which might be more suited to your needs:
var received = document.querySelector("_2her");
if (received.title == "Delivered") {
chColorsForDelivered();
}
var active;
var bg;
var received;
var rightDelivered;
var colorchint;
window.onload = function() {
main();
}
//=================== FUNCTIONS ===================
async function main() {
active = await document.getElementsByClassName("_2v6o");
bg = document.getElementsByClassName("_673w");
received = await document.getElementsByClassName("_2her");
rightDelivered = document.getElementsByClassName("_2jnt");
colorchint;
bg[0].onmouseover = function() {clearInterv();}
rightDelivered[0].onclick = function() {clearDeliv();}
//await sleep(2000);
if (active[0].innerText == "Active on Messenger") {
chColorsForActive();
}
else if (received[0].title == "Delivered") {
await chColorsForDelivered();
}
}
//for delivered
async function chColorsForDelivered() {
y = 1;
for (var i = 0; i < 6; i++) {
chColorsDelivered();
await sleep(1000);
}
}
function chColorsDelivered() {
if (y === 1) {
color = "#1e1e1e";
y = 2;
} else {
color = "orange";
y = 1;
}
rightDelivered[0].style.background = color;
}
//accessories
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
I put it into async. First I tried to
await for the variable received = await document.getElementsByClassName("_2her"); (it wasn't enough)
then I tried to sleep for 2 seconds (it was working)
tried to await the inner function (it was working too) But i have no idea why is it working if I wait for the inner function. I doesn't make sense to me. If I delete the await chColorsForDelivered(); await here It's complaining about the title is undefiend.
If you run this script in your messenger you will see an orange blinking span in the conversation information (where you see the pictures and stuffs, just delete the if)(It's only blinking if you have a Delivered message).
Related
This problem is very annoying. So, I am making a scheduled trigger run every 24 hours. It simply gets items from one collection does some data processing then appends information to another collection. The functioning code works even when the function runs. But it will not let me save because there are "runtime" errors? Even though it was executed perfectly and returned.
Console Error
> result (JavaScript):
EJSON.parse('{"$undefined":true}')
I suppose this has something to do with returning. but when I return null I get this:
> result:
null
> result (JavaScript):
EJSON.parse('null')
when trying to save I get this at the top of the page:
runtime error during function validation
Function Code:
exports = async function() {
const usersCol = context.services.get("SchoologyDashCluster").db("SchoologyDashApp").collection("users");
const gradesCol = context.services.get("SchoologyDashCluster").db("SchoologyDashApp").collection("grades");
var usersCusor = await usersCol.find( ).toArray();
var gradesCusor = await gradesCol.find( ).toArray();
let insert = [];
for (let i = 0; i < usersCusor.length; i++) {
var user = usersCusor[i];
var userSavedGrades = gradesCusor[i].grades
var currentGrades = await getGrades(user.schoologyUID, user.consumerKey, user.secretKey);
var lastGraded = NaN;
let index = gradesCusor[i].grades.length - 1;
while (true) {
if (gradesCusor[i].grades[index].changed == 1) {
lastGraded = index;
break
}
index = index - 1;
}
console.log(lastGraded)
if (userSavedGrades[lastGraded].grades.ga == currentGrades.ga){
currentGrades = { changed : 0, time: new Date().getTime()};
} else {
currentGrades = {changed : 1, grades: currentGrades, time : new Date().getTime()};
}
gradesCol.updateOne(
{"user" : user._id},
{"$push" : {"grades" : currentGrades}}
)
}
// return usersCol.find( );
return null;
};
The answer was simple and now I feel ignorant. Instinctual I put the module imports at the top of the document. However this is incorrect and they need to be placed in the exports function, like so:
exports = function (x,y,z) {
const http = context.http;
return;
}
I am very new to Javascript and I am trying to utilize BestBuy's api to grab data on a specific sku number every 3 seconds.
The call to the api works as expected on its own but when I move the call inside a while loop, I do not get anything and the console.log in the function is not hit.
Not sure where to go from here and I am starting wonder if this api call can only be called by itself.
Would appreciate any help.
var bby = require('bestbuy')('<Actual BestBuy Api key in original code>');
var isSoldOut = true;
while(isSoldOut)
{
console.log("HERE");
bby.products(6465789,{show:'sku,name,salePrice,onlineAvailability,inStorePickup,onlineAvailabilityUpdateDate'}).then(function(data){
console.log(data);
if (data['onlineAvailability'] == false)
{
isSoldOut = false;
console.log(isSoldOut);
}
});
wait(3000);
}
function wait(ms)
{
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms);
}
Your while loops are constantly blocking the thread, so your callback function can't run.
Instead of the while loops, you can use an interval:
var bby = require('bestbuy')('<Actual BestBuy Api key in original code>');
function check() {
console.log("HERE");
bby.products(6465789,{show:'sku,name,salePrice,onlineAvailability,inStorePickup,onlineAvailabilityUpdateDate'}).then(function(data){
console.log(data);
if (data['onlineAvailability'] == false)
{
clearInterval(loop);
console.log("In Stock");
}
});
}
const loop = setInterval(check, 3000);
Even cleaner may be using async/await to wait 3 seconds after receiving each response:
var bby = require('bestbuy')('<Actual BestBuy Api key in original code>');
const wait = require('util').promisify(setTimeout);
async function check() {
console.log("HERE");
const data = await bby.products(6465789,{show:'sku,name,salePrice,onlineAvailability,inStorePickup,onlineAvailabilityUpdateDate'});
console.log(data);
if (data['onlineAvailability'] == false)
{
console.log("In Stock");
return;
}
await wait(3000);
}
check();
There are several points to improve your code:
Use setInterval to execute code in regular interval, instead of using spin lock in a while loop
Use async/await to improve readability
Instead of checking condition == false, simply check !condition
Instead of doing if(!condition){x = false}, simply do x = !condition
Use dot notation instead of bracket notation to access object property if the property name is not variable. This can take advantage of intellisense of IDE if the object shape is properly documented and reduce typo.
const t = setInterval(async () =>{
const data = await bby.products(6465789, { show: 'sku,name,salePrice,onlineAvailability,inStorePickup,onlineAvailabilityUpdateDate' });
console.log(data);
isSoldOut = !data.onlineAvailability;
console.log(isSoldOut);
if(isSoldOut)
{
clearInterval(t);
}
},3000);
I've been scouring similar problems but haven't seem to have found a solution that quite works on my end. So I'm working on a Discord bot that takes data from a MongoDB database and displays said data in the form of a discord embedded message using Mongoose. For the most part, everything is working fine, however one little section of my code is giving me trouble.
So I need to import an array of both all available users and the "time" data of each of those users. Here is the block of code I use to import said data:
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
Now this for loop references a function I made called getData which obtains the data from MongoDB by this method:
async function getData(field, value){
var data;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
data = result[value];
}
});
if(field == "user"){
return data.user;
}else if (field == "time"){
return data.time;
}else{
return 0;
}
So that for loop is where my errors currently lie. When I try to run this code and display my data through a discord message, I get this error and the message does not get sent:
(node:13936) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'time' of undefined
Now the strange thing is, this error does not happen every time. If I continue calling the command that triggers this code from my discord server, it's almost like a 50/50 shot if the command actually shows the message or instead gives this error. It is very inconsistent.
This error is confounding me, as the undefined part does not make sense to me. The objects that are being searched for in the mongoDB collection are definitely defined, and the for loop never exceeds the number of objects present. My only conclusion is that I'm doing something wrong with my asynchronous function design. I have tried altering code to use the getData function less often, or to not use awaits or asynchronous design at all, however this leaves my final discord message with several undefined variables and an eventual crash.
If anyone has any advice or suggestions, that would be very much appreciated. Just for reference, here is the full function that receives the data, sorts it, and prepares a string to be displayed on the discord server (though the error only seems to occur in the first for loop):
async function buildString(){
var string = "";
var totalObj;
var timeArray = [];
var userArray = [];
var stopSort = false;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
totalObj = result.length;
}
});
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
while(!stopSort){
var keepSorting = false;
for(i = 0; i < totalObj ; i++){
var target = await convertTime(timeArray[i]);
for(j = i + 1 ; j < totalObj ; j++){
var comparison = await convertTime(timeArray[j]);
if(target > comparison){
//Switch target time with comparison time so that the lower time is up front
var temp = timeArray[i];
timeArray[i] = timeArray[j];
timeArray[j] = temp;
//Then switch the users around so that the user always corresponds with their time
var userTemp = userArray[i];
userArray[i] = userArray[j];
userArray[j] = userTemp;
//The loop will continue if even a single switch is made
keepSorting = true;
}
}
}
if(!keepSorting){
stopSort = true;
}
}
//String building starts here
var placeArray = [':first_place: **1st', ':second_place: **2nd', ':third_place: **3rd', '**4th', '**5th', '**6th', '**7th', '**8th', '**9th', '**10th'];
for(i = 0; i < totalObj; i++){
string = await string.concat(placeArray[i] + ": " + userArray[i] + "** - " + timeArray[i] + " \n\n");
console.log('butt');
}
console.log("This String:" + string);
return string;
}
I think problem is you are trying to await function with callback, it will not work => access to data.time may run before data = result[value]. If you need await callback, you can use custom Promise (or use util.promisify, more info here)
Promise:
function findStats(options) {
return new Promise((resolve, reject) => {
return stats.find(options, function (err, result) {
if (err) {
return reject(err)
}
return resolve(result)
})
})
}
utils.promisify
const util = require('util');
const findStats = util.promisify(stats.find);
Now you can use await in your function
async function getData(field, value) {
try {
const result = await findStats({})
const data = result.value
if (field === 'user') {
return data.user
}
if (field === 'time') {
return data.time
}
return 0
} catch (error) {
// here process error the way you like
// or remove try-catch block and sanitize error in your wrap function
}
}
I have a pretty CPU intensive operation running in a JS function. To indicate to the user when it starts and stops, I am trying to display a badge. Here's what the code looks like:
function updateView() {
console.log(1)
document.getElementById('app-status').className = "badge badge-danger";
document.getElementById('app-status').textContent = "Processing";
console.log(2)
setTimeout(myUpdateView(), 0)
console.log(5)
document.getElementById('app-status').className = "badge badge-success";
document.getElementById('app-status').textContent = "Ready"; console.log(6)
}
function myUpdateView() {
console.log(3)
updateFlightParameters();
// Get departure airport.
var departureAirportICAO = $("#DEPARTURE_AIRPORT").val();
if (airports[departureAirportICAO] === undefined) {
alert("Departure airport is incorrect.");
} else {
departureAirport = airports[departureAirportICAO];
}
// Get arrival airport.
var arrivalAirportICAO = $("#ARRIVAL_AIRPORT").val();
if (airports[arrivalAirportICAO] === undefined) {
alert("Arrival airport is incorrect.");
} else {
arrivalAirport = airports[arrivalAirportICAO];
}
// Create waypoints.
createWaypoint(departureAirport);
createWaypoint(arrivalAirport);
// Create path. THIS FUNCTION CALLS SOME OTHER ASYNC FUNCTIONS.
generatePolylines(flightWaypoints);
console.log(4)
}
The problem is that the app-status element never changes it's color or text. Upon clicking the button that calls updateView(), the page hangs (to do the processing) without changing the element.
Does the heavy processing function return anything? This seems like a good idea for a do-while statement.
const doSomethingCool(){
let trackingVariable = false;
do{
result = setInterval(massiveCompute, 100)
if(result === true){
trackingVariable = true;
}
} while (trackingVariable == false)
I would make sure the computer has time to update the screen:
function doHeavyProcessing() {
for (var i=0;i<1000000000;i++) ;
document.getElementById('app-status').className = "badge badge-success";
document.getElementById('app-status').textContent = "Ready";
}
function updateView() {
document.getElementById('app-status').className = "badge badge-danger";
document.getElementById('app-status').textContent = "Processing";
setTimeout(doHeavyProcessing,100)
}
updateView()
.badge-danger { color:red }
.badge-success { color:green }
<div id="app-status"></div>
I'm currently struggling with a function call, when I call the function from an if statement it does work but when I call it from outside it doesn't, my if statement only checks which button was pressed but I'm trying to remove the function from the button and just call it as soon as my app starts.
We will look at fetchJokes() inside jokeContainer.addEventListener('click', event => {
This is my current code:
const jokeContainer = document.querySelector('.joke-container');
const jokesArray = JSON.parse(localStorage.getItem("jokesData"));
// Fetch joke count from API endpoint
async function sizeJokesArray() {
let url = 'https://api.icndb.com/jokes/count';
let data = await (await fetch(url)).json();
data = data.value;
return data;
}
// use API endpoint to fetch the jokes and store it in an array
async function fetchJokes() {
let url = `https://api.icndb.com/jokes/random/${length}`;
let jokesData = [];
let data = await (await fetch(url)).json();
data = data.value;
for (jokePosition in data) {
jokesData.push(data[jokePosition].joke);
}
return localStorage.setItem("jokesData", JSON.stringify(jokesData));;
}
const jokeDispenser = (function() {
let counter = 0; //start counter at position 0 of jokes array
function _change(position) {
counter += position;
}
return {
nextJoke: function() {
_change(1);
counter %= jokesArray.length; // start from 0 if we get to the end of the array
return jokesArray[counter];
},
prevJoke: function() {
if (counter === 0) {
counter = jokesArray.length; // place our counter at the end of the array
}
_change(-1);
return jokesArray[counter];
}
};
})();
// pass selected joke to print on html element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Fetch') {
fetchJokes(length);
} else if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
And I'm trying to do something like this:
// pass selected joke to print on HTML element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
By the way, I'm aware that currently, you can't actually iterate through the array elements using prev and next button without refreshing the page but I guess that will be another question.
Couldn't think of a better title.(edits welcomed)
Async functions are, as the name implies, asynchronous. In
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
you are calling fetchJokes before length = size is executed because, as you may have guessed, sizeJokesArray is asynchronous.
But since you are already using promises the fix is straightforward:
sizeJokesArray().then(fetchJokes);
If you have not fully understood yet how promises work, maybe https://developers.google.com/web/fundamentals/getting-started/primers/promises helps.