For some reason I can't set a variable from inside a arrow function that is set outside of it. This is using replit's database. When I send the message containing the embed in the arrow function it works, but it will be in separate embeds.
Here is my code:
ARDB.list().then(keys => {
const ARListEmbed = new Discord.MessageEmbed()
.setColor('#0099ff')
for (var I=0; I<keys.length; I++) {
ARDB.get(keys[I]).then(value => {
ARListEmbed.addField("["+(I+1)+"]"+" "+keys[I], value, true);
}));
};
message.channel.send(ARListEmbed);
});
Any and all help will be appreciated!
Thanks for your help! But I seemed to fix this myself.
Here is the code that worked somehow.
ARDB.list().then(keys => {
const Length = keys.length;
let Index = 0;
let ARListEmbed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('9NK Discord Server Auto Responses:')
.setURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=OfficialRickAstley')
for (var I=0; I<keys.length; I++) {
let Key = keys[I];
ARDB.get(keys[I]).then(value => {
Index++;
ARListEmbed.addField("["+(Index)+"]"+" "+Key, value, true);
if (Index == Length) {
message.channel.send(ARListEmbed);
};
});
};
});
This code works because Index can be changed within the arrow function and keeps it's changed value when the for loop loops again but ouside of the loop it says it's original self (0). So I send the message when Index == keys length.
Related
I've been working on a project and I'm currently working on a function which dynamically creates a dictionary data structure. The key used is the roll number of the student, and the value is the student's name.
But I'm unable to iterate through this dictionary. I've tried displaying the dictionary on console, but all I could see is an empty dictionary. I could see the elements in it, only if I expand it further. And when I display length using Obj.length on console, it displays 'undefined'. I've read on other questions that Obj.length only works on arrays(i.e., enumerable types), and I've tried using an array instead of a dictionary. In that case, it shows an empty array and would not show values unless I manually expand it. I've also tried Obj.keys() method on the dictionary, and I've encountered the same issue.
This is the function's code:
function dictGenerator(rollnos, selectedValue) {
var dict = {};
for(let i = 0; i < rollnos.length; i++) {
get(child(dbref, "RegisterNos/" + rollnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[rollnos[i]] = snapshot.val()["name"];
}
});
}
console.log(dict);
console.log(dict.length);
}
}
Any help on how I could iterate through my dictionary would be appreciated, Thank you.
Edit:
code implementation using promises.
function dictGenerator(regnos, selectedValue) {
const get_dict = async () => {
var dict = {};
for(let i = 0; i < regnos.length; i++){
get(child(dbref, "RegisterNos/" + regnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[regnos[i]] = snapshot.val()["name"];
}
});
}
return dict;
};
get_dict().then((dict) => {
console.log(dict);
});
}
Basing on comments made by VALZ and JaredSmith, this is the working code:
function dictGenerator(regnos, selectedValue) {
const get_dict = async () => {
var dict = {};
for(let i = 0; i < regnos.length; i++){
await get(child(dbref, "RegisterNos/" + regnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[regnos[i]] = snapshot.val()["name"];
}
});
}
return dict;
};
get_dict().then((dict) => {
console.log(dict);
});
}
}
This is a code Snippet from a discord bot im working on
It needs to load up data from an Enmap, adds information to that Array and then pushes it back in.
It successfully pulls that data, does all the transformations and additions, etc
and successfully pushes that data
however, it cant pull the new data until the program is re-started. It gets saved but
let locationDataArray = await data.get(locationDataKey);
doesnt seem to do pull this new version of the map unless the program is restarted
I am fairly stumped
const Commando = require('discord.js-commando');
const levenshtein = require('fast-levenshtein');
const Enmap = require("enmap");
const data = new Enmap({
name:"locationdata"
});
const settingsMap = new Enmap({
name:"locationSettings"
})
module.exports = class addConnection extends Commando.Command{
constructor(client){
super(client, {
name:"addconnection",
group:"management",
aliases:["connect"],
memberName:"addconnection",
userPermissions:['ADMINISTRATOR'],
description:"adds a connection between two zones",
examples: ['$addconnection <zone1>,<zone2>'],
throttling: {
usages: 1,
duration: 5
},
args:[{
key:'destinations',
prompt:'what are the two areas you want to connect (seperate them with a comma , )',
type:'string'
}]
});
}
async run(msg,args){
//get our guilds Information
let guildID = msg.guild.id;
let locationDataKey = guildID+"_mapData";
let locationDataArray = await data.get(locationDataKey);
//Our Guild Settings
let settingMapKey = guildID+"_setting";
let settings = await settingsMap.get(settingMapKey);
//chiefly out npcRoleID
let npcRole = await msg.guild.roles.get(settings.npcRoleID);
let connectionArray = await args.destinations.toLowerCase().split(",");
for(var i = 0; i < connectionArray.length; i++){
//make sure the item is valid
var distance = levenshtein.get(connectionArray[i], locationDataArray[0].name);
var closestDistance = distance;
var closestWord = locationDataArray[0].name;
for(var j = 0; j < locationDataArray.length; j++){
distance = levenshtein.get(connectionArray[i], locationDataArray[j].name);
if (distance < closestDistance){
closestDistance = distance;
closestWord = locationDataArray[j].name;
}
}
//make sure all the areas are valid and good
if(closestDistance < (closestWord.length/2)){
connectionArray[i] = closestWord;
}
else{
msg.channel.send("those channels don't seem to exist").then( msg => {
msg.delete(10000);
});
return;
}
}
//our array of connections now only contains valid options
//loop over our location data array
for(var i = 0; i< connectionArray.length; i++){
for(var j = 0; j < locationDataArray.length; j++){
//when we hit one of out LDA that has the same name as something in the connectionArray
//stop add the rest of the connection array to its connections
if(locationDataArray[j].name === connectionArray[i]){
for(var k = 0; k < connectionArray.length; k++){
if(locationDataArray[j].name == connectionArray[k]){
}
else{
if(!locationDataArray[j].connections.includes(connectionArray[k])){
await locationDataArray[j].connections.push(connectionArray[k]);
}
//get the role for the connection and the current channel
let role = await msg.guild.roles.find(role => role.name === connectionArray[k]);
let currentChannel = await msg.guild.channels.find(channel => channel.name === locationDataArray[j].channelName);
//the connection can read but not type in its connection
currentChannel.overwritePermissions(
role,
{
'SEND_MESSAGES':false,
'VIEW_CHANNEL':true,
'READ_MESSAGE_HISTORY':true
}
)
data.set(locationDataKey, locationDataArray);
msg.channel.send("Connected "+locationDataArray[j].name+" and "+connectionArray[k]);
}
}
}
}
}
}
}
I know this question is old and I'm hoping you've resolved this issue a long time ago, but for posterity's sake, and because people might find this question later, I'm going to answer it anyways.
The reason this happens is that you're creating a new instance of Enmap in this file, and presumably you have it declared in other files too. This causes a new "client" for Enmap to be created, with its own individual cache, and it's not possible for Enmap to update those instances.
The solution is to either attach your Enmap to a variable you carry around (such as, for example, the Client), or to create a separate node module that you import wherever you need it. Both of those options are described in more details in the Enmap documentation: https://enmap.evie.dev/usage/using-from-multiple-files
Disclaimer: I am the author of Enmap
newbie at JavaScript and Postman here.
I have set up a basic test in postman using JS to compare names in a web response to names in a data file. The array of names is in an external data csv file.
I want to loop through the array, but I get an error:
"ReferenceError | i is not defined"
Code:
var newResponse = responseBody;
let nameArray = data.name;
for (let i = 0; i < nameArray.length; i++) {
console.log(nameArray.length);
}
pm.test("Web vs. Data: Person", function() {
pm.expect(newResponse.Item[i].name).to.equal(nameArray.Item[i].person);
});
console.log(newResponse.Item[i].name);
console.log(nameArray.Item[i].person);
Your end scope "}" character missing please change with this code;
var newResponse = responseBody;
let nameArray = data.name;
for (let i = 0; i < nameArray.length; i++) {
console.log(nameArray.length);
pm.test("Web vs. Data: Person", function () {
pm.expect(newResponse.Item[i].name).to.equal(nameArray.Item[i].person);
});
console.log(newResponse.Item[i].name);
console.log(nameArray.Item[i].person);
}
let is block scoped so it will cause ReferenceError out of the for loop. The variable i will not be referred outside of the for loop. So you've to move your codeblock inside the for loop like below. Hope this helps :)
var newResponse = responseBody;
let nameArray = data.name;
for(let i = 0; i < nameArray.length; i++){
console.log(nameArray.length);
pm.test("Web vs. Data: Person" ,function(){
pm.expect(newResponse.Item[i].name).to.equal(nameArray.Item[i].person);
});
console.log (newResponse.Item[i].name);
console.log(nameArray.Item[i].person);
}
I'm trying to grab data from chrome extension storage, but I can use them only in this function.
var help = new Array();
chrome.storage.local.get(null, function(storage){
//get data from extension storage
help = storage;
console.log(storage);
});
console.log(help); // empty
Result in console:
content.js:1 content script running
content.js:11 []
content.js:8 {/in/%E5%BF%97%E9%B9%8F-%E6%99%8F-013799151/: "link", /in/adam-
isaacs-690506ab/: "link", /in/alex-campbell-brown-832a09a0/: "link",
/in/alex-davies-41513a90/: "link", /in/alex-dunne-688a71a8/: "link", …}
Async function has won. I wrote my code again and now function is called hundreds time, i can not do this in dirrefent way
code:
console.log("content script running");
var cards = document.getElementsByClassName("org-alumni-profile-card");
var searchText = "Connect";
function check(exi, cards) {
chrome.storage.local.get(null, function(storage) {
for (var key in storage) {
if (storage[key] == "link" && key == exi) {
cards.style.opacity = "0.3";
}
}
});
}
for (var i = 0; i < cards.length; i++) {
var ctd = cards[i].getElementsByClassName(
"org-alumni-profile-card__link-text"
);
var msg = cards[i].getElementsByClassName(
"org-alumni-profile-card__messaging-button-shrunk"
);
if (ctd.length < 1 || msg.length > 0) {
cards[i].style.display = "none";
} else {
var exi = cards[i]
.getElementsByClassName("org-alumni-profile-card__full-name-link")[0]
.getAttribute("href");
check(exi, cards[i]);
}
}
SOLUTION of my problem
I wanted to delete this topic, but I can not, so instead of doing that, I'll put here what I've done finally.
The code above is wrong becouse, it was taking a list of links from website and for each from them script was grabbing a data from a storage... Which was stupid of course. I didn't see a solution which was so easy:
Put all your file's code in this function - it grabs data from storage just once.
I'm so sorry for messing up this wonderfull forum with topic like this.
Hope u'll forgive.
help will return undefined because it is referencing a asynchronous function and not the return value of that function. The content from storage looks to be printed on content.js:8, i.e. line 8.
I am making a call to an API. The API returns a list of results. When it does so - the response is fed into an object which I then use to iterate through and display them.
Here is the function which does that:
var getAvailability = () => {
if (chosenData.hotel == "") {
showError("Please select a location before booking.");
$timeout(() => LTBNavService.setTab('location'), 50);
return;
}
searchResponse = {};
console.log(searchResponse);
WebAPI.getHotelAvailability(genSearchObject()).then((data) => {
searchResponse = data;
$timeout(() => $('[data-tab-content] .search-btn').first().focus(), 50);
generateRoomTypeObject(searchResponse);
}, (data) => searchResponse.error = data.data.errors[0].error);
};
The Problem:
The old results are still displayed until the new set of results are available. This causes a flicker and a delay which is a bad user experience.
The solution:(which i need help with)
What is the best possible way of handling this problem? Ideally, I would like to reset/clear the search response. As in, the new results are delivered and the old ones are cleared. Is this possible from within the getAvailability function?
What would be the best way to achieve this?
The Solution:
Thanks to #Daniel Beck for his suggestion to call the generateRoomTypeObject function and feed it an empty object - +1'd his comment.
This triggered an undefined error in my generateRoomTypeObject function where i was running a few length checks(makes sense, because the object was empty - so there was nothing to do length checks on).
I handled the error by handling the undefined exception and setting the searchResponse to an empty object.
var generateRoomTypeObject = (searchResponse) => {
var ratePlans = searchResponse.ratePlans,
errors = searchResponse.error,
roomTypes = [],
ignoreBiggerRooms = false;
rawRoomsObjs = [];
if (angular.isUndefined(errors)) {
// Iterate over the rate plan
if(ratePlans === undefined){
//generateRoomTypeObject -- Handle undefined by creating new object
searchResponse = {}
}else{
for (var i = 0; i < ratePlans.length; i++) {
var ratePlan = ratePlans[i],
rooms = ratePlan.rooms;
// Iterate over the rooms and add rooms to room object. Also keep a list of room types.
for (var j = 0; j < rooms.length; j++) {
//Stuff here
}
}
}
}