I am facing critical issue in recursive function. This is my recursive function:
iterateJson(data, jsonData, returnedSelf) {
var obj = {
"name": data.groupName,
"size": 4350,
"type": data.groupType
};
if (data.parentGroupName == jsonData.name) {
jsonData.children.push(obj);
} else {
if (jsonData.children) {
for (var i = 0; i < jsonData.children.length; i++) {
if (data.parentGroupName == jsonData.children[i].name) {
jsonData.children[i].children.push(obj);
elementFound = true;
break;
}
}
if (elementFound) {
return jsonData;
} else {
if (jsonData.children) {
for (i = 0; i < jsonData.children.length; i++) {
if (elementFound) {
return jsonData;
} else {
jsonData = jsonData.children[i];
jsonData = returnedSelf.iterateJson(data, jsonData, returnedSelf);
}
}
}
}
}
}
return jsonData;
},
Now the problem is that, in the second for loop, (jsonData.children.length)
my jsonData is getting changed. how to retain the parent jsonData .
Hope my question is clear.
Editing to make it more precise.
suppose initially jsondata has 5 elements and i enter the loop took first children as new jsonData and call this function again. so when the condition will get fulfilled, it should return to for loop and jsonData should have that initial element of 5 data. rather than that, it is having new json data which is first child element of original jsonData.
My ask is how to retain that parent jsonData with 5 element.
As I Do not know about input data but
jsonData = jsonData.children[i];
jsonData = returnedSelf.iterateJson(data, jsonData, returnedSelf);
This are only lines who can override jsonData.
Related
(React web app development)
In order to check if the current stock status of products, I use ID of products to loop through json data.
I am trying to retrieve value of "DATAPAYLOAD" by key (id) from json (below). idsent is string passed from another component. But "if (Data.response[i].id === idsent)" this condition always appears to be false because I got "failed" in console.
That would be really helpful if someone could take a look at the following code and give me some sujections, thanks in advance!
onButtonClicked = () => {
const idsent="D56F36C6038DFC8244F"
for (var i = 0; i < Data.response.length; i++) {
if (Data.response[i].id === idsent) {
name = Data.response[i].DATAPAYLOAD;
const word = '<INSTOCKVALUE>INSTOCK</INSTOCKVALUE>';
if (name.includes(word)) {
return true;
}
else {
return false;
}
}
console.log("failed");
}
The following is part of the json data that is requested through fetch get-method.
Data= {
"code": 200,
"response": [
{
"id": "CED62C6F96BD0E21655142F",
"DATAPAYLOAD": "<AVAILABILITY>\n <CODE>200</CODE>\n
<INSTOCKVALUE>OUTOFSTOCK</INSTOCKVALUE>\n</AVAILABILITY>"
},
{
"id": "D56F36C6038DFC8244F",
"DATAPAYLOAD": "<AVAILABILITY>\n <CODE>200</CODE>\n
<INSTOCKVALUE>LESSTHAN10</INSTOCKVALUE>\n</AVAILABILITY>"
},
{
"id": "4536C9E608B563A749",
"DATAPAYLOAD": "<AVAILABILITY>\n <CODE>200</CODE>\n
<INSTOCKVALUE>INSTOCK</INSTOCKVALUE>\n</AVAILABILITY>"
},
{
"id": "3A576872130625CABFADEE68",
"DATAPAYLOAD": "<AVAILABILITY>\n <CODE>200</CODE>\n
<INSTOCKVALUE>INSTOCK</INSTOCKVALUE>\n</AVAILABILITY>"
}
]
}
Thank you again.
You probably wanted console.log("failed"); outside of the for loop like the following (so that it only executes once all the data is processed):
onButtonClicked = () => {
const idsent="D56F36C6038DFC8244F"
for (var i = 0; i < Data.response.length; i++) {
if (Data.response[i].id === idsent) {
name = Data.response[i].DATAPAYLOAD;
const word = '<INSTOCKVALUE>INSTOCK</INSTOCKVALUE>';
if (name.includes(word)) {
return true;
}
else {
return false;
}
}
}
console.log("failed");
When the fetch is successful, You need to read and parse the data using json(). Pleas read this
onButtonClicked = async () => {
const idsent="D56F36C6038DFC8244F"
Data = await Data.json(); // json() will create a promise
for (var i = 0; i < Data.response.length; i++) {
if (Data.response[i].id === idsent) {
name = Data.response[i].DATAPAYLOAD;
const word = '<INSTOCKVALUE>INSTOCK</INSTOCKVALUE>';
if (name.includes(word)) {
return true;
}
else {
return false;
}
}
console.log("failed");
}
The reason you get failed, is because the first time through, the ID does not match the one sent, so it console logs the "failed" message. Then the second time through the for loop it matches the data, and then hits the next if, which checks for the value. Since the value you are searching for is included in the data, it returns true and the for loop is exited. The reason you see the fail log is because you are logging when the id doesn't match and there are 3 records in that array where the id don't match, the first one being one of them.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm still very new to JavaScript, but the basic premise of my program is to make an API call, and then turn that data into a table. I have tested the buildHtmlTable function and it works fine with a sample array that I pre-populated with static data (not from API).
In the buildHtmlTable function console.log(myList.length) returns 0. This is most likely where to problem stems from because if length is 0 then for (var i = 0; i < myList.length; i++ does not run at all.
I've also tried adding data to my table using .push and seem to get the same errors.
Here is what my code looks like:
<body onLoad="buildHtmlTable('#excelDataTable')">
<table id="excelDataTable" border="1">
</table>
</body>
<script>
var myList = [];
function getAPIData() {
// Create a request variable and assign a new XMLHttpRequest object to it.
var request = new XMLHttpRequest()
// Open a new connection, using the GET request on the URL endpoint
request.open('GET', '/api/table=1/records/', true)
request.onload = function () {
// Begin accessing JSON data here
var data = JSON.parse(this.response)
n = 0
if (request.status >= 200 && request.status < 400) {
data.forEach(record => {
myList[n] = (record.data);
n++;
//console.log(record.data.name)
})
} else {
console.log('error')
}
}
request.send()
console.log('fin')
}
// Builds the HTML Table out of myList.
function buildHtmlTable(selector) {
getAPIData()
console.log(myList.length)
console.log(1)
var columns = addAllColumnHeaders(myList, selector);
console.log(1.1)
console.log(myList.length)
for (var i = 0; i < myList.length; i++) {
console.log(1.2)
var row$ = $('<tr/>');
console.log(1.3)
for (var colIndex = 0; colIndex < columns.length; colIndex++) {
var cellValue = myList[i][columns[colIndex]];
if (cellValue == null) cellValue = "";
row$.append($('<td/>').html(cellValue));
}
$(selector).append(row$);
}
console.log(2)
}
// Adds a header row to the table and returns the set of columns.
// Need to do union of keys from all records as some records may not contain
// all records.
function addAllColumnHeaders(myList, selector) {
var columnSet = [];
var headerTr$ = $('<tr/>');
for (var i = 0; i < myList.length; i++) {
var rowHash = myList[i];
for (var key in rowHash) {
if ($.inArray(key, columnSet) == -1) {
columnSet.push(key);
headerTr$.append($('<th/>').html(key));
}
}
}
$(selector).append(headerTr$);
return columnSet;
}
</script>
As for the requested data, this is what the returned JSON looks like:
[
{
"id": 1,
"data": {
"name": "John Doe",
"id": "5d7861f38319f297df433ae1"
}
},
{
"id": 2,
"data": {
"name": "John deer",
"id": "5d7861f38319f297df433ae1"
}
},
{
"id": 3,
"data": {
"name": "Jane Doe",
"id": "5d79126f48ca13121d673300"
}
}
]
Any idea on where I am going wrong here? Thanks.
Edit: Here is what my implementation using fetch. However, I'm still getting an array with a length of 0.
async function getAPIData() {
const response = await fetch('/api/table=1/records/')
const myJson = await response.json();
myJson.forEach(record => {
myList.push(record.data);
})
}
XMLHttpRequests are asynchronous, meaning the rest of your code won't wait for them to finish before they run. When you call getAPIData(), it starts making the request, but then it goes to the next line of buildHtmlTable before the request is complete (and thus before the list is populated). What you should be doing is calling the getAPIData function outside the buildHtmlTable function, then calling buildHtmlTable in the onload callback of the XHR request. This will ensure the data is loaded and populated by the time the HTML building function is run.
You could also switch to using fetch instead of XMLHttpRequest; since fetch returns a promise, you can use the ES6 async / await syntax to just await the API response before the code inside the buildHtmlTable function continues. But that's a new way to think about AJAX and asynchronous behavior, so if you're not used to it, I'd say stick to my first suggestion instead.
I've run into an interesting dilemma- I want to write a function which, given a couple parameters, will return an object/parameter in a JSON response based on the value of another.
Snippet 1 shows a way that I could do it with simple case checking:
function callf() {
return f("name", "project_id", "sampleName");
}
function f(Where, Return, Is) {
var options = {
"option1": "asdf",
"option2": "asdf"
}
var url = "..."
var response = UrlFetchApp.fetch(url, options);
var jsonResponse = JSON.parse(response.getContentText());
for (i in jsonResponse) {
if (Where == "object1") {
//Instead of dynamically calling the object, use case testing to call the desired object.
if (jsonResponse[i].object1 == Is) {
if (Return = "returnValue1") {
return jsonResponse[i].returnValue1;
} else if (Return = "returnValue2") {
return jsonResponse[i].returnValue2;
}
}
} else if (Where == "object2") {
if (jsonResponse[i].object2 == Is) {
if (Return = "returnValue1") {
return jsonResponse[i].returnValue1;
} else if (Return = "returnValue2") {
return jsonResponse[i].returnValue2;
}
}
}
}
However, with doing it the way above, I have to account for every possible object that the json response contains, that would be a pain. I want to find an alternative where I can simply pass the a string representing the object I want to return from a function like the snippet below:
function callf(){
return f("name","project_id","sampleName");
}
function f(Where,Return,Is){
var options = {
"option1":"asdf",
"option2":"asdf"
}
var url = "..."
var response = UrlFetchApp.fetch(url,options);
var jsonResponse = JSON.parse(response.getContentText());
for(i in jsonResponse){
if(jsonResponse[i].(Where)==Is){
return jsonResponse[i].(Return);
}
}
}
How might I accomplish this?
Just like you're accessing json with i variable as key using square brackets,
for(var i in jsonResponse){
if(jsonResponse[i][Where]==Is){
return jsonResponse[i][Return];
}
}
var arrayOfId[] = $scope.rep.Selected.id;
I have this code. My question is if I had a some id's in $scope...Selected.id and then I make this (code) all these id's will be in every other array or in one array?
$scope.delIt = function () {
if ($scope.rep.Selected > 0) {
$scope.rep.Selected = true;
} else {
$scope.rep.Selected = false
}
var arrayOfId [] = $scope.rep.Selected.id;
for(i=0; i<=arrayOfId[i]; i++){
$http.delete("http://localhost:3000/users/" +arrayOfId[]);
}
}
This is full code. I wanted to send request every single id wich is stored in $scope.rep.Selected.id
There is an exception occurring and I am not sure why because I am new to JS. As soon as I reach the line testData["beacons"].append(beacon); My code jumps to catch(e). I am assuming I cant append objects to other arrays?
JS:
$(document).ready(function() {
// Data to describe what kind of test
var testData = {
"timestamp": "",
"hive": 0,
"hdfs": 0,
// Contains a list of testData objects
"beacons":[]
};
var testRun = document.getElementById("test-form");
testRun.addEventListener('submit', function(event) {
event.preventDefault();
var selectedTest = document.querySelector('input[name=test-select]:checked');
alert(selectedTest);
var testType = selectedTest.id;
if (testType == "hdfs-test") {
testData["hdfs"] = 1;
testData["hive"] = 0;
} else if (testType == "hive-test") {
testData["hdfs"] = 0;
testData["hive"] = 1;
} else if (testType == "hdfs-hive-test") {
testData["hdfs"] = 1;
testData["hive"] = 1;
} else {
// null
}
var events = document.getElementById("event-textarea").value;
// check in valid input
var eventSource = events.replace("],[","],,,,[");
// beaconLists allows users to submit --> [{beacon1}, {beacon2}, ...], [{beacon3}, {beacon4}, ...]
var beaconLists = eventSource.split(",,,,");
for (var i = 0; i < beaconLists.length; i++) {
// inspect one list in beaconLists [{beacon1}, {beacon2}, ...]
var beaconList = beaconLists[i];
try {
// list of JSON objects
var beaconObjList = JSON.parse(beaconList);
for (var j = 0; j < beaconObjList.length; j++) {
var beaconObj = beaconObjList[j];
if (beaconObj["data"] && beaconObj["application"]) {
// successful parse to find events
// describe beacon being tested
alert("yes");
var beacon = {
"app_name": beaconObj["application"]["app_name"],
"device": beaconObj["application"]["device"],
"device_id": beaconObj["application"]["device_id"],
"os": beaconObj["application"]["os"],
"os_version": beaconObj["application"]["os_version"],
"browser": beaconObj["application"]["browser"],
"beacon": beaconObj
};
// append to testData
testData["beacons"].append(beacon);
// reset beacon so we can append new beacon later
beacon = {};
} else {
// notify event isn't in the correct format?
alert("no");
}
}
} catch (e) {
// notify bad JSON
alert("failed");
}
}
console.log(testData);
//$.ajax({
// type: "POST",
// url: "/test/",
// data: testData,
// success: function () {
// alert("yay");
// },
// failure: function () {
// alert("boo");
// }
//});
});
});
There is nothing wrong with having an array of objects. JavaScript handles that just fine. The main issue is that append is a jQuery API method for adding elements (psuedo native appendChild). push is how you add to an array.
testData["beacons"].push(beacon);
Further, this part of your code is problematic.
// reset beacon so we can append new beacon later
beacon = {};
Both the variable beacon and the one added here testData["beacons"] are the same. In JavaScript, the value of testData["beacons"]'s recent beacon is the same as the variable beacon. When the value in the variable beacon is set to {}, so is the array's value. This line of code simply needs to be removed. Inside of the variable environment set up, the use of var will set up a new variable for beacon each iteration.
You should use the push method, like:
testData["beacons"].push(beacon);