select data by clicking buttons, then combine associated CSVs into one array - javascript

I'm creating an interface where a user can click on buttons that have the names of CSVs in order to see the combined data they select charted.
I've set it up so that each button click adds the name of a CSV to an array (called chosenData). Then I'm using a for loop to cycle through the chosenData array, grab the data from github, and push all of the data into another array called allData.
However, the data doesn't combine correctly. I've been pulling my hair out over this problem for hours and haven't been able to resolve it, so any help would be greatly appreciated!
Code below. Here's also a jsfiddle
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>combine CSVs</title>
</head>
<body>
<button id="arr1" class="button">arr1</button>
<button id="arr2" class="button">arr2</button>
<button id="arr3" class="button">arr3</button>
<button id="arr4" class="button">arr4</button>
<button id="arr5" class="button">arr5</button>
<script>
var parseTime = d3.timeParse("%Y-%m")
let chosenData = []
let allData = []
$('.button').on('click', d => {
let data = event.target.id
console.log(data)
chosenData.push(data)
console.log('chosenData', chosenData)
obtainData(chosenData)
})
function obtainData(chosenData) {
for (i = 0; i < chosenData.length; i++) {
let arrayName = chosenData[i]
let dailyData = axios.get("https://raw.githubusercontent.com/sprucegoose1/sample-data/main/" + chosenData[i] + ".csv")
.then(content => {
let single = content.data
let singleCSV = d3.csvParse(single)
singleCSV.forEach(d => {
d.value = +d.value
d.interval = +d.interval
d.time = +d.time
d.code = arrayName
d.date = parseTime(d.date);
})
console.log('single data', singleCSV)
allData.push(singleCSV)
})
}
const merge = allData.flat(1);
chartData(merge);
}
function chartData(allData) {
console.log('all data', allData)
// create a chart with combined data here
}
</script>
</body>
</html>

The issue is probably that the fetches are async. You start them in the for loop, but you don't wait for them before you do the flattening and call chartData.
You could push the promises returned by axios.get in the loop to ann array, then after the loop use Promise.all to wait for all of them before you merge.

Related

How to get REST API JavaScript fetch object value to HTML?

How can I get printed console object value to HTML?
I have JavaScript fetch code like this:
const comments = fetch("https://api.github.com/repos/pieceofdiy/comments/issues/1")
.then((response) => response.json())
.then((labels) => {
return labels.comments;
});
const printComments = () => {
comments.then((number) => {
console.log(number);
});
};
printComments()
printComments() numeric object value shows correct in console, but how to show it in HTML
to <span id="comments">..</span> ?
With JS you can edit the DOM Hierarchy by searching for your desired Element to change.
const commentsEl = document.querySelector('.comments');
commentsEl.innerHTML = printComments();
With document.querySelector(CSS-Selector) you can search the DOM-Tree for a sufficient Element matching your Selector
We store the Element in a variable and change the Content of this Element by saving the comments in the property .innerHTML.
I've added a snippet demonstrating the changes below, and also changed some bits to improve your code.
As the fetch-Method is asynchronous, you’ll see fetching comments ... for a brief moment, as we change the content when the fetch finished and we got the results.
const commentsEl = document.querySelector('.comments');
// We fetch the comments as before
fetch("https://api.github.com/repos/pieceofdiy/comments/issues/1")
.then((response) => response.json())
.then((labels) => {
// But when we get the results, we immedietly change the contents of the comments span.
commentsEl.innerHTML = labels.comments;
});
<div class="container">
<p>Comments:</p>
<span class="comments">Fetching comments ...</span>
</div>
You could try setting a p tag with an id, ex: <p id=“comments”>and then using document.getElementById(“comments”).innerValue = number;
Place that second piece of code into printComments()
First you need to get your span tag in your html document.
Then define the innerHtml property of the span element by the value returned by the promise, in this case in your case the value is returned through a callback, so you simply have to perform the process in the scope of the callback.
Here is a snippet to illustrate this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<span id="comments"></span>
<script>
const span = document.getElementById("comments");
const comments = fetch("https://api.github.com/repos/pieceofdiy/comments/issues/1")
.then((response) => response.json())
.then((labels) => {
return labels.comments;
});
comments
.then(res => span.innerHTML = res)
.catch(err => console.log(err));
</script>
</body>
</html>
But it can be done more cleanly this way:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ol>
<li>Comments: <span id="comments1"></span></li>
<li>Comments: <span id="comments2"></span></li>
<li>Comments: <span id="comments3"></span></li>
</ol>
<script>
const comments1 = document.getElementById("comments1");
const comments2 = document.getElementById("comments2");
const comments3 = document.getElementById("comments3");
const printComment = async (url, HTMLTag) => {
try {
const request = await fetch(url);
const response = await request.json();
HTMLTag.innerHTML = response.comments;
} catch (error) {
console.log(error);
}
};
printComment("https://api.github.com/repos/pieceofdiy/comments/issues/1", comments1);
printComment("https://api.github.com/repos/pieceofdiy/comments/issues/1", comments2);
printComment("https://api.github.com/repos/pieceofdiy/comments/issues/1", comments3);
</script>
</body>
</html>
Good luck !

Add multiple values to localStorage and then retrieve a random one in JavaScript

I am trying to make a system where the user inputs multiple values at separate times and then can click a button that tells them one of their inputs (at random). This is what I have so far:
(Note: for some odd reason this code snippet is not functioning properly here (at least not on my side) but it is working just fine in JS Bin and even my own Notepad++)
function store(){
var toStore = document.getElementById("itemInputBox");
localStorage.setItem("itemInputBox", toStore.value);
}
function get(){
var toGet = localStorage.getItem("itemInputBox");
document.getElementById("outputArea").innerHTML = toGet;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<form id="itemForm">
<input type="text" id="itemInputBox" autocomplete="off" onmouseout="store()"><br><br>
<button id="getStoredValue" onclick="get()" type="button" style="cursor:pointer;">Get Input Value</button>
</form>
<div id="outputArea"></div>
</body>
</html>
As I am fairly new to coding (have been doing it for only a year or so) and I am also new to localStorage, I need some guidance for this. Thanks to whoever responds!
You can use Arrays in Javascript to store multiple values in the localStorage. When storing the values, they should be in JSON format. Also, when retrieving the values you have to pass that JSON string to `JSON.parse(array) and then retrieve the values.
To get a random value from that array, you can use Math functions in JavaScript. Please check the example below. It won't work in the StackOverflow code snippets section because it restricts the LocalStorage functions but you can check it locally.
function store(){
var toStore = document.getElementById("itemInputBox");
var valuesJSON = get();
if (valuesJSON == null){
createLocalStorageKey();
}
var values = JSON.parse(get());
values.items.push(toStore.value);
localStorage.setItem("itemInputBox", JSON.stringify(values));
}
function createLocalStorageKey(){
localStorage.setItem("itemInputBox", JSON.stringify({items:[]}));
}
function get(){
var toGet = localStorage.getItem("itemInputBox");
return toGet;
}
function parseValueToHTML(){
var valuesJSON = get();
if (valuesJSON == null){
createLocalStorageKey();
}
var values = JSON.parse(get());
document.getElementById("outputArea").innerHTML = values.items[Math.floor(Math.random() * values.items.length)];
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<form id="itemForm">
<input type="text" id="itemInputBox" autocomplete="off"><br><br>
<button onclick="store()" type="button">Store Value</button>
<button id="getStoredValue" onclick="parseValueToHTML()" type="button" style="cursor:pointer;">Get Input Value</button>
</form>
<div id="outputArea"></div>
</body>
</html>
You can use an array to store your values
Before you add a new value you'll have to retrieve the array from local storage
Add the new value to the array and replace the previous array in local storage with the updated one
Use JSON to serialize the data to store it in local storage
If there is no data in local storage create an array with the value
For the get functionality, after you retrieve the array you can generate a random number from 0 to the length of the array-1 to choose a value by index.
my way...
const itemForm = document.forms['item-form']
, getAllItems = _ =>
{
let r = localStorage.getItem('itemInputBox')
return !r ? [] : JSON.parse(r)
}
, setAllItems = arr =>
{
localStorage.setItem('itemInputBox',JSON.stringify(arr))
}
;
itemForm.setValueStored.onclick=()=>
{
let val = itemForm.itemInputBox.value.trim()
if (val)
{
let store = getAllItems()
if (!store.include(val))
{
store.push(val)
setAllItems(store)
}
}
itemForm.itemInputBox.value = ''
}
itemForm.getStoredValue.onclick=()=>
{
let store = getAllItems()
itemForm.itemInputBox.value = (!store.length) ? '' : store[Math.floor(Math.random() *store.length)]
}
<form name="item-form">
<input type="text" name="itemInputBox" autocomplete="off">
<br><br>
<button name="setValueStored" type="button">Set value in store</button>
<button name="getStoredValue" type="button">Get random input value from store</button>
</form>

How can I fetch data from an API, process the data and render everything after the data was parsed?

My problem is that while fetching data from an API the website is already loaded, so for a second or so I see the default data in the elements and only after that the element data is updated.
I've already tried many ways like Async/Await and Promises and also events like jQuery.ready(), window.onload(), and the DOMContainerLoaded event on the fetch method but everytime, the page loads first.
In short, I want to (in order):
Get the data from an API (json)
Parse the data to an Object
Updated the elements on the page with the data
Render the whole page
This is what I have at the moment:
Player.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="/css/main.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="/public/js/classes.js" charset="utf-8"></script>
<script src="/public/js/player.js" charset="utf-8"></script>
</head>
<body>
<div class="container">
<img id="playerAvatar" class="avatar" alt="The avatar of the player">
<h2 id="nick"></h2>
<!-- More Stuff Later -->
</div>
</body>
</html>
player.js
window.addEventListener('DOMContentLoaded', async function(){
const player = await processPlayerData();
fillPlayerData(player);
});
async function processPlayerData(){
const user = new URLSearchParams(window.location.search).get('id');
const json = await requestData('/api/player/'+ user, {method: "GET"});
let player = new Player();
if("errors" in json)
player = null;
else
player.fillData(json);
return player;
}
async function requestData(dir, options) {
const response = await fetch(dir, options)
.then((response) => { return response.json(); });
return response;
}
function fillPlayerData(player){
if(player === null)
alert("The user does not exist!");
else{
document.getElementById('nick').innerHTML = "AlexMFV"; //player.nickname;
document.getElementById('playerAvatar').src = "https://media.gettyimages.com/photos/colorful-powder-explosion-in-all-directions-in-a-nice-composition-picture-id890147976?s=612x612"; //player.avatarUrl;
//Fill the elements with all the player data
//Get all player matches
}
return true;
}
And also on the server I have a method that is gathering the JSON from the API:
async function getPlayerData(req, res){
let value;
try{
const user = req.params.id;
value = await fetch(strPlayerData.replace('<usr>', user), packet).then((res) => { return res.json(); });
res.json(value);
}
catch(e){
error(res, e);
}
}
If there is something that you don't understand please tell me so that I can provide more information.
Edit: If you want to try it so that you can see what I mean, the project is available here: https://faceitstats.alexmfv.com/player.html?id=Alex

Marketing cloud SSJS - javascript passing values between 2 scripts

I have a cloud pages.
On this page , i have
SSJS script , which retrives records from a data extension. From the count column in the data extension , i want to create a array like
dataarray = [10,20,30,40,50]
Then i need to pass this array (dataarray ) to another script where i can use it in d3.
The problem i am facing is how to pass values from a script which run at server to a script which run in client . I have tried hidden html element method which does not work and does not garrentte seq of script execution.
can you please advise how to pass values .
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="https://www.abc.nl/favicon.ico">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
</head>
<body>
<script runat="Server">
Platform.Load("core","1.1.5");
var data_rec;
try
{
var myDE = DataExtension.Init('01_Reporting_Sent_Today');
var filter = {Property:'return',SimpleOperator:'equals',Value:'1'};
var data = myDE.Rows.Retrieve(filter);
data_rec = data.length;
Write("<br/>The len is :" + Stringify(data_rec))
}catch(ex)
{
Write("<br/>The error is :" + Stringify(ex))
}
</script>
<script>
var datachart = [10,20,30,40,50];
var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500)
var bars = canvas.selectAll("rect")
.data(datachart)
.enter()
.append("rect")
.attr("width",function (d) { return d;})
.attr("height",50);
</script>
</body>
</html>
so the dataarray from first script , i need to use in second script
You can use AMPScript to return the value inside the JS script:
Update: fixed incorrect syntax in my example as pointed out by Reidenshi
<script runat="server">
...
var dataString = Stringify(data);
Variable.SetValue("#dataString", dataString);
</script>
<script>
var data = JSON.parse(%%=v(#dataString)=%%);
</script>

why bindCallback is not a function?

Hi I am using this rxjs libraray .I am getting this error
Rx.Observable.bindCallback is not a function
here is my code
http://jsbin.com/tuxucotake/edit?html,js,console,output
I am reading doc from here
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html
var getJSONAsObservable = Rx.Observable.bindCallback(jQuery.getJSON);
var result = getJSONAsObservable('http://mysafeinfo.com/api/data?list=englishmonarchs&format=json');
result.subscribe(x => console.log(x), e => console.error(e));
You are using RXJS 4 but the docs you have linked to are RXJS 5
Based on #Günter Zöchbauer answer, bindCallback() is not anymore part of Observableso the correct usage for current version of RxJs (6) would be:
jsbin
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<title>JS Bin</title>
</head>
<body>
</body>
</html>
js
var getJSONAsObservable = rxjs.bindCallback(jQuery.getJSON);
var result = getJSONAsObservable('https://mysafeinfo.com/api/data? list=englishmonarchs&format=json');
result.subscribe(
([data,textStatus,jqXhr]) => console.log(data),
e => console.error(e));
Respectively for node:
const Rx = require('rxjs')
const {bindCallback} = Rx;
var getJSONAsObservable = bindCallback(jQuery.getJSON);
....

Categories

Resources