Codestructure in async javascript - javascript

I have a simple program that reads a css file (which is available on GitHub pages) and parse the css to an array so I can put at in a list.
I have an dictionary with words, like a vocabulary list which shows me the translation and I can also search for words.
Everything works fine so far but I am really new and this is my first project and I want some advise about my codestructure.
At the moment I have to fetch the csv file (which never changes) in different methods with getData. I do this in init dictionary and again in search and show, because I need the dictionary again. Wouldn’t it be better to get the data once and then use it with all functions?
But then I have to write a lot function into another which is not so good practice I think.
I would really appreciate some advise or link or topics/ direction I have to research, because I can’t find an answer about how to structure this well.
I just use html, css and js without any framework or library.
initDictionary();
async function initDictionary(){
//get data
const dictionary = await getData();
//fill html list with words
fillList(dictionary);
}
//show translation and info when click on word
show = async function (i){
let dictionary = await getData();
document.getElementById("word-text").innerHTML = dictionary[i].Wort;
document.getElementById("info").innerHTML = dictionary[i].Notizen;
}
//search stuff
search = async function() {
let dictionary = await getData();
let query = document.getElementById('search').value;
console.log(query);
if (query == ""){
return;
}
//init found to false
let found = -1;
for(let i=0; i< dictionary.length; i++){
if(query == dictionary[i].Übersetzung){
found = i;
break;
}else {
document.getElementById("word-text").innerHTML = "word not found";
document.getElementById("info").innerHTML ="";
}
}
if ( found >= 0){
show (found);
query = document.getElementById('search').value="";
}
}
//Start search when u press enter
let input = document.getElementById("search");
input.addEventListener("keyup", function(event) {
console.log(event);
if (event.key=== "Enter") {
search();
}
});
// get data
async function getData(){
const csv = await fetch('https://aboutwhite.github.io/data/data.csv');
let scvText = await csv.text();
let dictionary = csvToArray(scvText);
return dictionary;
}
// fill html list with words
function fillList(dictionary){
for(let i=0; i< dictionary.length; i++){
document.getElementById('word-list').innerHTML += "<li onclick='show("+i+")'>" + dictionary[i].Übersetzung+"</li>";
}
}
//parse csv to array
function csvToArray(str){
let delimiter = ","
const headers = str.slice(0, str.indexOf("\n")).split(delimiter);
const rows = str.slice(str.indexOf("\n") + 1).split("\n");
const arr = rows.map(function (row) {
const values = row.split(delimiter);
const el = headers.reduce(function (object, header, index) {
object[header] = values[index];
return object;
}, {});
return el;
});
return arr;
}

Related

JavaScript Obj.length method returns undefined despite dictionary containing elements

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

How to fetch and display a specific index in a JSON file using a Javascript loop

I am currently using fetch in javascript to obtain information from another site into my own. The issue I am having is, I am using a loop to display all of the indexes of the JSON file into my site. I actually want to get specific indexes to show, not all of them, for example, index 2,4 and 6.
Here is my code so far:
window.addEventListener("load", (event)=>{
const requestURL = 'https://byui-cit230.github.io/weather/data/towndata.json';
fetch(requestURL)
.then(function (response) {
return response.json();
})
.then(function (jsonObject) {
const towns = jsonObject['towns'];
for (let i = 0; i < towns.length; i++ ) {
let towninfo = document.createElement('section');
let townname = document.createElement('h2');
townname.textContent = towns[i].name;
towninfo.appendChild(townname);
document.querySelector('div.weathertowns').appendChild(towninfo);
}
});
})
This displays all of the towns in reference, but I only want to display the title of 3 specific ones. Any suggestions on how to proceed with this?
something like that
window.addEventListener("load", (event)=>
{
const requestURL = 'https://byui-cit230.github.io/weather/data/towndata.json'
, divWeathertowns = document.querySelector('div.weathertowns')
;
fetch(requestURL)
.then( response=>response.json() )
.then( jsonObject=>
{
const towns = jsonObject['towns']
;
for ( let i of [2,4,6] )
{
let towninfo = document.createElement('section')
, townname = document.createElement('h2')
;
townname.textContent = towns[i].name;
towninfo.appendChild(townname);
divWeathertowns.appendChild(towninfo);
}
});
})
<div class="weathertowns"></div>

How can I overwrite and append data to the same file multiple times in node js

I have a "clients.txt" file where I have a list of emails. I try to run a program for sending emails where I chose a number of emails to use from the file, in that case the number is 2. After I use the two emails I want to overwrite "clients.txt" without them. The problem is when I try to run the code just for one single time every thing is working! but if I make a loop something is wrong. Looking forward to see any help from you guys. Thanks! I add the code bellow. PS: Sorry for my bad english!
function readEmails(){
const fs = require('fs');
clients_list = fs.readFileSync('clients.txt', 'utf8').split('\n');
let filtered = clients_list.filter(function (el) {
return el != null && el != '';
});
return filtered
}
function dump_array(arr, file){
let fs = require('fs');
let file = fs.createWriteStream(file);
file.on('error', function(err) { /* error handling */ });
arr.forEach(function(v) { file.write(v + '\n'); });
file.end();
}
while_var = 0;
while (while_var < 2){
while_var ++;
let all_clients = readEmails();
let selected_clients = [];
if (all_clients.length > 0){
selected_clients = all_clients.splice(0,2);
dump_array(all_clients, 'clients.txt');
console.log(selected_clients);
}else{
console.log('No more clients')
}
}
const fs = require('fs');
function readEmails(){
const clients_list = fs.readFileSync('clients.txt', 'utf8').split('\n');
const filtered = clients_list
// clear false, 0 and undefined too
.filter(el => !!el)
// remove extra spaces and \r symbols
.map(el => el.trim());
return filtered;
}
function dump_array(arr, file){
// Here you need sync method.
fs.writeFileSync(file, arr.join('\n'));
// And here was 'already declared' error in orginal code
}
let while_var = 0;
while (while_var++ < 2){
let all_clients = readEmails();
let selected_clients = [];
if (all_clients.length > 0){
selected_clients = all_clients.splice(0,2);
dump_array(all_clients, 'clients.txt');
console.log(selected_clients);
}else{
console.log('No more clients')
}
}

JavaScript - Issues recovering a map in an object after being saved in localStorage

I've been dealing with this for some time. I've a list of sections in which the user checks some checkboxes and that is sent to the server via AJAX. However, since the user can return to previous sections, I'm using some objects of mine to store some things the user has done (if he/she already finished working in that section, which checkboxes checked, etc). I'm doing this to not overload the database and only send new requests to store information if the user effectively changes a previous checkbox, not if he just starts clicking "Save" randomly. I'm using objects to see the sections of the page, and storing the previous state of the checkboxes in a Map. Here's my "supervisor":
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
var children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children().length;
for (var i = 0; i < children; i++) {
if (i % 2 == 0) {
var checkbox = $("#ContentPlaceHolder1_checkboxes_div_" + id).children()[i];
var idCheck = checkbox.id.split("_")[2];
this.selections.set(idCheck, false);
}
}
console.log("Length " + this.selections.size);
this.change = false;
}
The console.log gives me the expected output, so I assume my Map is created and initialized correctly. Since the session of the user can expire before he finishes his work, or he can close his browser by accident, I'm storing this object using local storage, so I can change the page accordingly to what he has done should anything happen. Here are my functions:
function setObj(id, supervisor) {
localStorage.setItem(id, JSON.stringify(supervisor));
}
function getObj(key) {
var supervisor = JSON.parse(localStorage.getItem(key));
return supervisor;
}
So, I'm trying to add to the record whenever an user clicks in a checkbox. And this is where the problem happens. Here's the function:
function checkboxClicked(idCbx) {
var idSection = $("#ContentPlaceHolder1_hdnActualField").val();
var supervisor = getObj(idSection);
console.log(typeof (supervisor)); //Returns object, everythings fine
console.log(typeof (supervisor.change)); //Returns boolean
supervisor.change = true;
var idCheck = idCbx.split("_")[2]; //I just want a part of the name
console.log(typeof(supervisor.selections)); //Prints object
console.log("Length " + supervisor.selections.size); //Undefined!
supervisor.selections.set(idCheck, true); //Error! Note: The true is just for testing purposes
setObj(idSection, supervisor);
}
What am I doing wrong? Thanks!
Please look at this example, I removed the jquery id discovery for clarity. You'll need to adapt this to meet your needs but it should get you mostly there.
const mapToJSON = (map) => [...map];
const mapFromJSON = (json) => new Map(json);
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
this.change = false;
this.selections.set('blah', 'hello');
}
Supervisor.from = function (data) {
const id = data.id;
const supervisor = new Supervisor(id);
supervisor.verif = data.verif;
supervisor.selections = new Map(data.selections);
return supervisor;
};
Supervisor.prototype.toJSON = function() {
return {
id: this.id,
verif: this.verif,
selections: mapToJSON(this.selections)
}
}
const expected = new Supervisor(1);
console.log(expected);
const json = JSON.stringify(expected);
const actual = Supervisor.from(JSON.parse(json));
console.log(actual);
If you cant use the spread operation in 'mapToJSON' you could loop and push.
const mapToJSON = (map) => {
const result = [];
for (let entry of map.entries()) {
result.push(entry);
}
return result;
}
Really the only thing id change is have the constructor do less, just accept values, assign with minimal fiddling, and have a factory query the dom and populate the constructor with values. Maybe something like fromDOM() or something. This will make Supervisor more flexible and easier to test.
function Supervisor(options) {
this.id = options.id;
this.verif = null;
this.selections = options.selections || new Map();
this.change = false;
}
Supervisor.fromDOM = function(id) {
const selections = new Map();
const children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children();
for (var i = 0; i < children.length; i++) {
if (i % 2 == 0) {
var checkbox = children[i];
var idCheck = checkbox.id.split("_")[2];
selections.set(idCheck, false);
}
}
return new Supervisor({ id: id, selections: selections });
};
console.log(Supervisor.fromDOM(2));
You can keep going and have another method that tries to parse a Supervisor from localStorageand default to the dom based factory if the localStorage one returns null.

how to read/use imported table from API into javascript?

I am using an API from Caspio to import a Data Table that will be variable.
for that, I am doing the following
<script type="text/javascript" id='Test' src="https://c1afw487.caspio.com/dp/6e444000877ca58e63624b0b8c78/emb"></script>
and then to format it (send it to the bottom of my web page) I am doing this:
<div id='InfoTable' style='width: 40%; float: left;'>
<a id='TestTwo' href="https://c1afw487.caspio.com/dp/6e444000877ca58e63624b0b8c78">DataTable </a>
</div>
Now, I am trying to access the data from the table. For that I am trying something like this
var DataTest = document.getElementById('Test');
var DataTestTwo = document.getElementById('TestTwo');
console.log(JSON.stringify(DataTest));
console.log(JSON.stringify(DataTestTwo));
But the first test returns { } and the second one null (notice how I tried to give an ID to the imported table so I could access it but any of my attempts worked).
What is the proper way to access the Table?
I dont know anything about that specific API but quick google seems to suggest that they have a separate rest api for requesting JSON data. You should look into that.
Stringifying an html element does nothing usefull...its an html element not your request payload data.
You can go over the table itself and extract all the contents into a json.
Something like this.
https://jsfiddle.net/rainerpl/wvdoek03/14/
var getHeaders = (table) => {
const headerRow = table.tBodies[0].children[0];
const headers = [];
let i;
for (i = 0; i < headerRow.children.length; i++) {
headers.push(headerRow.children[i].innerText);
}
return headers;
}
var getData = (table) => {
const data = [];
let i;
for (i = 1; i < table.tBodies[0].children.length; i++) {
let newDataRow = [];
for (j = 0; j < table.tBodies[0].children[i].children.length; j++) {
newDataRow.push(table.tBodies[0].children[i].children[j].innerText);
}
data.push(newDataRow);
}
return data;
}
JsonTable = function() {
const table = document.getElementsByTagName('table')[0];
const headers = getHeaders(table);
const data = getData(table);
this.getRow = (rowNr) => {
const result = {};
headers.forEach((key, index) => {
result[key] = data[rowNr][index];
});
return result;
}
console.log('table', table, 'has data:', data, ' and headers ', headers);
}
const jsonTable = new JsonTable();
console.log('First row is', jsonTable.getRow(0));
console.log('Second row is', jsonTable.getRow(1));
You can view the console output on jsFiddle to see what it looks like.
( use inspect developer tool to see console output )

Categories

Resources