Javascript - Help retrieving data from Firebase - javascript

I have this code below to retrive data from firebase and turn into an array but whenever i call it it stops other functions from being called inside the code even tho I can perfectly call them in the console.
I've worked around this by using callback functions but I am at a point it just doesn't do anymore. How can make this part act like a normal function where I can call anytime without stopping the code.
function genList(){
dataRef.on('value', data => {
let arr = (data.val());
let keys = Object.keys(arr);
for (let i = 0; i < keys.length; i++) {
let k = keys[i];
let title = arr[k].title;
let author = arr[k].author;
let pages = arr[k].pages;
let date = arr[k].date;
let bookmark = arr[k].bookmark;
let newList = new Object();
newList.title = title;
newList.author = author;
newList.pages = pages;
newList.date = date;
newList.bookmark = bookmark;
bookList.push(newList);
}
})}

Related

AppScript API returning empty JSON object

So, I'm trying to build an API using my Google Sheet and I've run into a problem.
Here's my code
function doGet() {
let doc = SpreadsheetApp.getActiveSpreadsheet();
let sheet = doc.getSheetByName('portfolios');
let values = sheet.getDataRange().getValues();
let output = [];
for (let i = 2; i < values.length; i++) {
let row = [];
row['name'] = values[i][0];
row['committee'] = values[i][1];
row['post'] = values[i][2];
//console.log(row)
output.push(row);
}
console.log(output)
return ContentService.createTextOutput(JSON.stringify(output)).setMimeType(ContentService.MimeType.JSON);
}
When I run the script, I get the desired output in the console but when I deploy the API (I've set "Who has access" to Everyone) and send a GET request, I receive an empty JSON object.
[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
What am I doing wrong?
On behalf of OP, Himanshu Sardana
I was able to fix the error, turns out it was due to me using the JSON.stringify function incorrectly. I was able to fix it by changing:
let row = [];
to
let row = {};
Edited code:
function doGet() {
let doc = SpreadsheetApp.getActiveSpreadsheet();
let sheet = doc.getSheetByName('portfolios');
let values = sheet.getDataRange().getValues();
let output = [];
for (let i = 2; i < values.length; i++) {
let row = {}; // Edit in question
row['name'] = values[i][0];
row['committee'] = values[i][1];
row['post'] = values[i][2];
//console.log(row)
output.push(row);
}
console.log(output)
return ContentService.createTextOutput(JSON.stringify(output)).setMimeType(ContentService.MimeType.JSON);
}

Cannot push JSON elements to array inside for loop called from useEffect

I have an array candleRealTimeDataQueue which is not getting updated properly. Please find the code below:
let candleCurrentJSONDataWS = null;
var candleRealTimeDataQueue = [];
let tempDateTime = null;
let candleJsonData = {};
useEffect(() => {
getDataFromAPI();
}, []);
...
const getDataFromAPI = async () => {
let apiDataFetch = await fetch('https:/api/endpoint');
let response = await apiDataFetch.json(); // data from api obtained correctly
// total 4 values
for (var i = 0; i < 4; i++) {
tempDateTime = new Date(parseInt(response[i][0]));
candleJsonData['time'] = tempDateTime.toString();
candleJsonData['open'] = parseFloat(response[i][1]);
candleJsonData['high'] = parseFloat(response[i][2]);
candleJsonData['low'] = parseFloat(response[i][3]);
candleJsonData['close'] = parseFloat(response[i][4]);
console.log(candleJsonData); // this correctly prints different
// data for each different i
candleRealTimeDataQueue.push(candleJsonData);
console.log(candleRealTimeDataQueue); // PROBLEM is here: At the end
// candleRealTimeDataQueue array all
// have SAME elements. Its wrong. All
// 4 elements are of i = 3
}
}
Problem is at the end candleRealTimeDataQueue has 4 elements and all the elements are same. This should not happen because I am pushing DIFFERENT candleJsonData elements in the candleRealTimeDataQueue array in the for loop. Please help.
I believe the problem here is that you are reusing the candleJsonData object. When you run candleRealTimeDataQueue.push(candleJsonData), you are pushing the reference to candleJsonData into candleRealTimeDataQueue. So at the end of the loop, you have four references to the same object inside candleRealTimeDataQueue. And since you are modifying the same candleJsonData object over and over again, you'll just see four identical json data inside the queue when you log it and all four elements will be of i = 3.
Instead, you should be creating new candleJsonData objects inside your loop. So something like
for (var i = 0; i < 4; i++) {
tempDateTime = new Date(parseInt(response[i][0]));
let candleJsonData = {}
candleJsonData['time'] = tempDateTime.toString();
candleJsonData['open'] = parseFloat(response[i][1]);
candleJsonData['high'] = parseFloat(response[i][2]);
candleJsonData['low'] = parseFloat(response[i][3]);
candleJsonData['close'] = parseFloat(response[i][4]);
candleRealTimeDataQueue.push(candleJsonData);
}
it is because of the candleJsonData variable which is declared outside, so latest value is overriding previous value. In face there is no need of that variable and it can directly push in the array.
var candleRealTimeDataQueue = [];
React.useEffect(() => {
getDataFromAPI().then((data) => {
for (let i = 0; i < 4; i++) {
candleRealTimeDataQueue.push({
time: new Date(parseInt(data[i][0])).toString(),
open: parseFloat(data[i][1]),
low: parseFloat(data[i][3]),
close: parseFloat(data[i][4]),
});
}
});
return () => {
// do clean up here
};
}, []);
const getDataFromAPI = () => {
return fetch('https:/api/endpoint');
};

for loop not making multiple buttons correctly

So i'm trying to make multiple buttons with a for loop such as
const buttonSection = document.getElementById('listOfFiles');
for (let i = 0; i < arrayOfFiles.length; i++){
const questionnaireSelector = document.createElement('input');
questionnaireSelector.type = 'button';
questionnaireSelector.id = 'selectorButton' + i;
questionnaireSelector.value = arrayOfFiles[i];
buttonSection.appendChild(questionnaireSelector);
and instead of making a button for each element in the arrayOfFiles array which is populated earlier on in the code, it makes one button and instead just writes all of the contents of the array into the value of that one button.
Would anyone be able to help?
Thanks
I have added the necessary missing elements. You should replace them.
HTML:
<div id='listOfFiles'></div>
JS:
const buttonSection = document.getElementById('listOfFiles');
const arrayOfFiles = [1,2,3,4] // to be replaced
for (let i = 0; i < arrayOfFiles.length; i++){
const questionnaireSelector = document.createElement('input');
questionnaireSelector.type = 'button';
questionnaireSelector.id = 'selectorButton' + i;
questionnaireSelector.value = arrayOfFiles[i];
buttonSection.appendChild(questionnaireSelector);
}
see it in action
I figured it out, because the contents of the array are retrieved from the server in array form already, when i push it to arrayOfFiles it becomes a nested array. Which is why it only makes one button as it takes the index[0] of the encapsulating array. Full code :
"use strict";
const arrayOfFiles = [];
async function getListFromServer(){
const response = await fetch('/api/viewQuestionnaires');
const directory = await response.json();
arrayOfFiles.push(directory);
}
function displayListOfFiles(){
revealButton.remove();
const buttonSection = document.getElementById('listOfFiles');
for (let i = 0; i < arrayOfFiles.length; i++){
let questionnaireSelector = document.createElement('input');
questionnaireSelector.type = 'button';
questionnaireSelector.id = 'selectorButton' + i;
questionnaireSelector.value = arrayOfFiles[i];
buttonSection.appendChild(questionnaireSelector);
}
}

Best method for calling function parameters in a for loop?

So I'm working with some slightly tricky code. Basically, I'm trying to pull a <script> tag from around 10 pages on a site I'm developing for. This code's syntax is incorrect, as you cannot use brackets in function parameters, but it's the essence of what I'm trying to perform:
var parser = new DOMParser();
var resp = new Array();
var htmlDoc = new Array();
var findScripts = new Array();
var searchScripts = new Array();
var scriptContent = new Array();
for (var i = 0; i < amt; i++) {
resp[i] = prodDetails[i].responseText;
htmlDoc[i] = parser.parseFromString(resp[i],"text/html");
findScripts[i] = htmlDoc[i].body.querySelectorAll('script');
searchScripts[i] = Array.prototype.filter.call(findScripts[i], function (findScripts[i]) {
return RegExp('var prodInfo = ').test(findScripts[i].textContent);
});
scriptContent[i] = searchScripts[i].innerText;
}
Further, possibly unneeded details:
I'm using the following code to grab each page:
var text = "";
var prodDetails = new Array();
var amt = document.querySelectorAll('[id="product-details"]').length;
for (var i = 0; i < amt; i++) {
prodDetails[i] = $.get(itemPages[i].href, {}, function (results) {
});
}
Following this, I am then parsing the information so that the tag can be pulled through simple JavaScript commands:
var parser = new DOMParser();
var resp = new Array();
var htmlDoc = new Array();
for (var i = 0; i < amt; i++) {
resp[i] = prodDetails[i].responseText;
htmlDoc[i] = parser.parseFromString(resp[i],"text/html");
}
This works for accessing each page's DOM individually by calling htmlDoc[0] through htmlDoc[9], but there are around 8 <script> tags on each of the pages. The one that I'm looking for contains specific text in its innerHTML. I can find the one I'm looking for using:
var findScripts = htmlDoc[0].body.querySelectorAll('script');
var searchScripts = Array.prototype.filter.call(findScripts, function (findScripts) {
return RegExp('var prodInfo = ').test(findScripts.textContent);
});
var scriptContent = searchScripts[0].innerText;
This code works great when ran on its own, but this means manually running each time changing the index value of htmlDoc, and I'm looking for more of an "all at once" solution.
I'm not opposed to using jQuery in this, but I am mostly unfamiliar with it. If there is a more powerful jQuery-based solution, I will take that as well. Any help is appreciated! Thank you!
Rather than assigning to someArr[i] and someOtherArr[i] over and over, I suggest just pushing to the arrays in question instead, the code will look a lot cleaner. Also, you can use forEach for better abstraction, to avoid manual iteration, and to avoid the problems with i hoisting:
const parser = new DOMParser();
const responseTexts = [];
const htmlDocs = [];
const findScripts = [];
const filteredScripts = [];
const scriptContent = [];
prodDetails.forEach((response) => {
const responseText = response.responseText;
const newDoc = parser.parseFromString(responseText,"text/html");
const thisDocScripts = newDoc.querySelectorAll('script');
const thisDocFilteredScripts = [...thisDocScripts]
.filter(oneScript => oneScript.textContent.includes('const prodInfo = '));
const thisDocScriptsContent = thisDocFilteredScripts.map(scr => scr.textContent);
responseTexts.push(responseText);
htmlDocs.push(newDoc);
findScripts.push(thisDocScripts);
filteredScripts.push(thisDocFilteredScripts);
scriptContent.push(thisDocScriptsContent);
});
Abstraction is wonderful.
Do you really need all of those variables saved in arrays, though?

Why is Data Null?

I came across an error today, and I am not sure why it occurred. At the second for loop, the access to data will be undefined instead of the data that was inserted as a parameter into the function. Somehow the data gets the value of null, instead of the Object that was passed to this function. Does anyone know why? The error I get is "data is not defined".
createDataObject: function (data) {
let dataObj = data.source[0];
let backedData = data.backedData;
for (let i in dataObj) {
let d = dataObj[i];
d.data = { source: d.data };
}
for (let i = 0; i < data.backedData.length; i++) {
let bd = data.backedData[i]; //<- this is where the error occurrs
let data = bd.data[0];
}
}
Here is some code outside of the object, if you want to try, that I was using, this will work on your console or in node. Seems like I have come across a Javascript compiler bug. I am not sure.
createDataObject({source: [[{data: 1}]], backedData: [1,2,3, 4]});
The code above will work if I do the following
createDataObject: function (data) {
let dataObj = data.source[0];
let backedData = data.backedData; //create the backedData variable here
for (let i in dataObj) {
let d = dataObj[i];
d.data = { source: d.data };
}
for (let i = 0; i < backedData.length; i++) {
let bd = backedData[i]; // no Error
let data = bd.data[0];
//.....
}
}
in the second for loop you create another data object. Data is not created on the first line in the for loop.
Try using
for (let i = 0; i < data.backedData.length; i++) {
let bd = data.backedData[i];
let d= bd.data[0]; // Convert data to d or another variable name
//.....
}

Categories

Resources