Recursion with Javascript on JSON data - javascript

So, I have this function.
function makeContent(jsonData) {
var aProperty,
containerType,
contentContainerName,
containerIdentifier,
containerComment,
theContent;
console.log("jsonData = ");
console.log(jsonData);
var madeContent;
for (aProperty in jsonData) {
console.log("Working on property " + aProperty);
console.log("With value of ");
console.log(jsonData[aProperty]);
switch (aProperty) {
case "containerType": {
containerType = jsonData[aProperty];
break;
}
case "contentContainerName": {
contentContainerName = jsonData[aProperty];
break;
}
case "containerComment": {
containerComment = jsonData[aProperty];
break;
}
case "containerIdentifier": {
containerIdentifier = jsonData[aProperty];
break;
}
case "itemContent": {
theContent = jsonData[aProperty];
break;
}
}
}
if (typeof theContent !== 'undefined') {
console.log("theContent =");
console.log(theContent);
if (theContent.hasOwnProperty) {
if (madeContent != 'undefined') {
madeContent = makeContent(theContent);
madeContent = "<" + containerType + " " + containerIdentifier + "=\"" + contentContainerName + "\">" + madeContent + "</" + containerType + ">" + containerComment;
}
} else {
madeContent = "<" + containerType + " " + containerIdentifier + "=\"" + contentContainerName + "\">" + theContent + "</" + containerType + ">" + containerComment
console.log(madeContent);
console.log("Else statement");
}
}
return madeContent;
}
My trouble doesn't start until after the recursive call. For some reason after I call the makeContent() again in a recursive way, in the for loop to go through the properties in the object, I get 0 for the aProperty.
The JSON Data:
{
"contentContainerName" : "footer-bgcontent",
"containerType" : "div",
"containerIdentifier" : "id",
"containerComment" : "<!-- End #footer-bgcontent-->",
"itemContent" : [
{
"contentContainerName" : "footer",
"containerType" : "div",
"containerIdentifier" : "id",
"contentComment" : "<!-- End #footer -->",
"itemContent" : [
{
"contentContainerName" : "footerLink",
"containerType" : "a",
"containerIdentifier" : "id",
"contentTag" : ""
},
{
"contentContainerName" : "footerContent",
"containerType" : "div",
"containerIdentifier" : "id",
"contentTag" : "<div id=\"footerContent\"></div><!-- End #footerContent-->",
"itemContent" : [
{
"contentContainerName" : "createdBy",
"containerType" : "p",
"containerIdentifier" : "id",
"contentTag" : "<p id=\"createdBy\"></p>",
"itemContent" : "Created by: Patrick McAvoy"
},
{
"contentContainerName" : "lastModified",
"containerType" : "p",
"containerIdentifier" : "id",
"contentTag" : "<p id=\"lastModified\"></p>",
"itemContent" : "Last Modified: "
},
{
"contentContainerName" : "copyright",
"containerType" : "p",
"containerIdentifier" : "id",
"contentTag" : "<p id=\"copright\"></p>",
"itemContent" : "Copright"
}
]
}
]
}
]
}
Then the output
jsonData =
footer.js:51
Object
footer.js:55Working on property contentContainerName
footer.js:56With value of
footer.js:57footer-bgcontent
footer.js:55Working on property containerType
footer.js:56With value of
footer.js:57div
footer.js:55Working on property containerIdentifier
footer.js:56With value of
footer.js:57id
footer.js:55Working on property containerComment
footer.js:56With value of
footer.js:57<!-- End #footer-bgcontent-->
footer.js:55Working on property itemContent
footer.js:56With value of
footer.js:57[
Object
]
footer.js:83theContent =
footer.js:84[
Object
]
footer.js:50jsonData =
footer.js:51[
Object
]
footer.js:55Working on property 0
footer.js:56With value of
footer.js:57
Object
footer.js:38Made content:
footer.js:39<div id="footer-bgcontent">undefined</div><!-- End #footer-bgcontent-->

I'm unsure if this is causing your problem, but this line is wrong:
if (theContent.hasOwnProperty)
.hasOwnProperty is a method of every object/type in JS, so the test above is always true and so your code will always recurse, even if .itemContent is a string.
In any event, the code is unnecessarily complicated - there's no need to iterate through all the properties and test each key - just assign them directly to the required variables!
I believe the below code replicates what you're trying to do and is much shorter!
function makeContent(data) {
var type = data.containerType || 'div',
name = data.contentContainerName || '',
id = data.containerIdentifier || 'id',
comment = data.containerComment || '',
content = data.itemContent || '';
if (Array.isArray(content)) {
content = content.map(makeContent).join('');
}
return '<' + type + ' ' + id + '="' + name + '">' + content +
'</' + type + '>' + comment;
}
where the || 'foo' ensures the strings are assigned default values if not specified.
See http://jsfiddle.net/alnitak/rmTTg/ - NB: this code does nothing with the contentTag proeprty which is also unused in your own code.

Related

Javascript: Unable to retrieve values in an object which has function

Using Javascript, I wrote this code to create an object:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
Now, i'm interested in printing each property & its value so i wrote this code:
for (let eachEle in employee){
if(typeof eachEle=='string' || typeof eachEle=='number'){
console.log(eachEle + ":" + employee[eachEle]);
}
else if(typeof eachEle=='function'){
console.log(eachEle + ":" + employee.eachEle());
}
}
But, on executing, it works fine except for "emp_fullname" & "emp_bonus". Instead of showing the value, it shows me the function:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function() {
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal: "QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary: 13579,
emp_bonus: function() {
return (this.emp_salary * 1);
}
};
for (let eachEle in employee) {
if (typeof eachEle == 'string' || typeof eachEle == 'number') {
console.log(eachEle + ":" + employee[eachEle]);
} else if (typeof eachEle == 'function') {
console.log(eachEle + ":" + employee.eachEle());
}
}
How am I supposed to retrieve the value for those two properties? I'm looking for answers using which I can modify the for...in loop & retrieve the value.
How am i supposed to retrieve the value for those two properties?
The function is the value of those properties. If you want to get the return value of the function, you have to call it.
Note that the typeof check you're doing in your for-in loop is unnecessary. The eachEle variable is the property name, not the property value. In a for-in loop, the name will always be a string. (Not all properties are named with strings, but for-in only covers the ones that are.)
You want to get the value of the property, check if it's a function, and if so call it:
for (let name in employee){
let value = employee[name];
if (typeof value === "function") {
value = employee[name]();
}
console.log(name + ":" + value);
}
Live Example:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let name in employee){
let value = employee[name];
if (typeof value === "function") {
value = employee[name]();
}
console.log(name + ":" + value);
}
You said you just wnated to change the loop, but another approach is to change the object definition to use an accessor property rather than an explicit function:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
get emp_fullname() {
// ^^^ ^^
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
get emp_bonus() {
// ^^^ ^^
return (this.emp_salary*1);
}
};
Then the loop doesn't have to check:
for (let name in employee){
console.log(name + ":" + employee[name]);
}
Live Example:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
get emp_fullname() {
// ^^^ ^^
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
get emp_bonus() {
// ^^^ ^^
return (this.emp_salary*1);
}
};
for (let name in employee){
console.log(name + ":" + employee[name]);
}
That works because when you get the value of an accessor property, its accessor function is run behind the scenes and that function's return value is provided as the property value.
You need to check the type of value, eachEle is value of key which for your object is always string.
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function() {
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal: "QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary: 13579,
emp_bonus: function() {
return (this.emp_salary * 1);
}
};
for (let eachEle in employee) {
if (typeof employee[eachEle] == 'string' || typeof employee[eachEle] == 'number') {
console.log(eachEle + ":" + employee[eachEle]);
} else if (typeof employee[eachEle] == 'function') {
console.log(eachEle + ":" + employee[eachEle]());
}
}
Two things you need to change
You need to check for the value of element for string, number and function and not the key
While executing the function you need to use the brackets notation since its a dynamic key
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let key in employee){
let eachEle = employee[key];
if(typeof eachEle=='string' || typeof eachEle=='number'){
console.log(key + ":" + employee[key]);
}
else if(typeof eachEle=='function'){
console.log(key + ":" + employee[key]());
}
}
Your mistakes are:
1. You wrote: typeof eachEle insted of: typeof employee[eachEle]:
2. The execute is: employee.eachEle() insted of employee[eachEle](). eachEle is a string.
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let eachEle in employee){debugger
if(typeof employee[eachEle]=='string' || typeof employee[eachEle]=='number'){
console.log(eachEle + ":" + employee[eachEle]);
}
else if(typeof employee[eachEle]=='function'){
console.log(eachEle + ":" + employee[eachEle]());
}
}
In your for loop, you iterate over the keys in the object, and those will never be objects. Instead, you should retrieve the item before checking its type.
for(let key in employee){
let value = employee[key];
if(typeof value=='string' || typeof vlaue=='number'){
console.log(key + ":" + value);
}
else if(typeof value=='function'){
console.log(key + ":" + value());
}
}

How to make variables optional while concatenation of string?

I am manipulating string to display in UI, Data is being dynamically with below code sometime i don't get header and details so how to make IHeader and IResponse optional for the string concatenation below.
if i dont have IHeader it will break at IHeader.id and throw exception i want to display whatever data is available to render.
main.js
const data = [{
id: "header",
name: "IHeader"
}, {
id: "param",
name: "IParams"
}, {
id: "details",
name: "IResponse"
}]
function buildText(data) {
var IParams;
var IResponse;
var IHeader;
for (var item of data) {
if (item.id === "param") {
IParams = item;
} else if (item.id === "header") {
IHeader = item;
} else if (item.id === "details") {
IResponse = item;
}
}
var text = '';
text += app + '.setConfig({\n' + "env:" + getEnv() + '\n});' + '\n\n';
text += 'let param:' + IParams.name + ' ' + '=' + '' + JSON.stringify(request, null, 4) + ';\n\n';
text += ref + '(' + 'param,(result:' + ' ' + '{' + '\n' + IHeader.id + ':' + IHeader.name + '\n' + IResponse.id + ':' + IResponse.name + '\n' + '})' + ' ' +
' => {\n console.log(result); \n});';
}
1 - You can try to create an object with empty values. That'll prevent the exception.
emptyObject = {id: ""} // more empty keys, if there is
IParam = (item.id === "param") ? item : emptyObject
2 - Or ignore that concatenation of the variable if undefined or null.
if (Iparam) {
// concatenation ..
}

How do I get values from an array?

I have an array which is in the following format:
RBS: [ {
"RegExp": "",
"Type": ""
} ],
PAN: [ {
"RegExp": "Date",
"Type": "Date"
} ]
Now I want to pass the value PAN to a method and it should get the count of PAN length 1 and get PAN of regex values and type value. How can I do this? I formed an array like this: Name holds RBS and PAN:
var Regexp = [];
RegExpr.push(Name + ":" + Regexp);
function Check(test) {
//test will be RBS /PAN
}
var obj = {
RBS:[{"RegExp":"","Type":""}],
PAN:[{"RegExp":"Date","Type":"Date"}]
};
function getTypeAndValue( obj, value )
{
var output;
var keys = Object.keys( obj );
if ( obj [value ] )
{
output = obj[ value ][ 0 ];
}
return output;
}
var value = getTypeAndValue( obj, "PAN" );
if ( value )
{
console.log( "type is " + value.Type + " and RegExp is " + value.RegExp );
}
else
{
console.log( "this value doesn't exists" );
}
You mean something like this?
HTML
<div id="count"></div>
<div id="detail"></div>
JAVASCRIPT
var countEl = document.getElementById("count");
var detailEl = document.getElementById("detail");
function Check(test){
var count = test.length;
countEl.innerHTML = "Count: " + count;
detailEl.innerHTML = "";
for (var i = 0 ; i < count ; i++){
var values = test[i];
detailEl.innerHTML +=
"<br/>" + (i +1) + ":<br/>" +
"RegExp: " + values["RegExp"] + "<br/>" +
"Type: " + values["Type"] + "<br/>";
}
}
var Name = {
RBS: [ {
"RegExp": "",
"Type": ""
} ],
PAN: [ {
"RegExp": "Date",
"Type": "Date"
} ]
};
Check(Name.PAN);
DEMO
Here's a JSFiddle.

Cannot read property of undefined - JavaScript

I have problem withe code geoloaction auto. When pressing the button, the current location has an error:
Uncaught TypeError: Cannot read property 'coords' of undefined
code:
var date = new Date();
var Today = date.getDay();
function loadWeather(cityCoords){
var latlng = cityCoords.coords.latitude + "," + cityCoords.coords.longitude;
var forecastURL = "https://api.forecast.io/forecast/3a6d5408bc15a469385cf59ee96c0205/" + latlng +"?lang=ar&si&raw";
$.ajax({
url: forecastURL,
jsonpCallback: 'jsonCallback',
contentType: "application/json",
dataType: 'jsonp',
success: function(json) {
updateCurrentWeather(json);
weeklyForecast(json);
},
error: function(e) {
console.log(e.message);
}
});
}
function updateCurrentWeather (json) {
$("#current_temp").html(Math.round(json.currently.temperature) + "; C");
$("#current_summary").html ( " الحالة الجوية : "+ json.currently.summary) ;
$("#current_temp").attr("data-icon",icons[json.currently.icon]);
$("#current_windSpeed").html( " الرياح : "+json.currently.windSpeed);
}
function weeklyForecast (json) {
var Day = Today;
var outhtml;
for ( var i = 0; i <= 6; i++)
{
outhtml = "";
Day = Day + 1
//check if day is greater than number in week
if ( Day === 7) {
Day = 0;
}
//format html
outhtml = '<li><h3 class="icon" data-icon="' + icons[json.daily.data[i].icon] + ' ">' + days[Day];
outhtml = outhtml + (json.daily.data[i].summary);
outhtml = outhtml + ", العليا " + Math.round(json.daily.data[i].temperatureMax) + "° C ";
outhtml = outhtml + " , صغرى " + Math.round(json.daily.data[i].temperatureMin) + "° C ";
outhtml = outhtml + '</h3></li>';
//append new html li item to list view
$(".WeekForecast").append(outhtml);
}
}
function loadDefaultCity() {
loadCity("Baghdad");
}
function loadCity(city) {
$("#location").html(city);
if (city.toLowerCase() == "current location") {
if ( navigator.geolocation ) {
navigator.geolocation.getCurrentPosition(loadWeather, loadDefaultCity);
} else {
loadDefaultCity();
}
} else {
loadWeather(cities[city.toLowerCase()]);
}
}
another data javascript appears cities[city.toLowerCase()] is defined
var icons = {
"clear-day" : "B",
"clear-night" : "C",
"rain" : "R",
"snow" : "G",
"sleet" : "X",
"wind" : "S",
"fog" : "N",
"cloudy" : "Y",
"partly-cloudy-day" : "H",
"partly-cloudy-night" : "I",
};
var cities = {
"baghdad" : { coords : { latitude : "33.3333", longitude: "44.3833" }},
"current location" : ""
};
var days = {
"0" : "الاحد : ",
"1" : "االاثنين : ",
"2" : ": الثلاثاء",
"3" : "الاربعاء : ",
"4" : "الخميس : ",
"5" : "الجمعة : ",
"6" : "السبت : "
};
var hours = {
"0" : "1",
"1" : "2",
"2" : "3",
"3" : "4",
"4" : "5",
"5" : "6",
"6" : "7",
};

javascript convert JSON string to JSON object

I al using javascript and looping through the values of a submitted form and trying to build a son object out of the form values.
This is an example of the final object I need:
{
"DataObject": {
"user": { "-name": "username" },
"contentFile": {
"-filename": "Breaking_News",
"lock": { "-fileIsBeingEdited": "false" },
"content": {
"line": [
{
"-index": "1",
"-text": "this is the header"
},
{
"-index": "2",
"-text": "this is the first line"
},
{
"-index": "3",
"-text": "this is the second line"
}
]
}
}
}
}
So far i am adding all of this data to a string as that seems to be the only way i can insert the form values (the line array) into the middle of the object.
var jsonStr = '{'
+ 'iceteaDataObject: {'
+ 'user: {"-name": "hindsc52"},'
+ 'contentFile: {'
+ '"-filename": "Ticker",'
+ 'lock: { "-fileIsBeingEdited": "false" },'
+ 'content: {'
+ 'line: ['
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
jsonStr += '{'
jsonStr += "-index: " + i + ',';
jsonStr += "-text: " + elem[i].value;
jsonStr += '},'
}
}
jsonStr += ']}}}}';
console.log(JSON.parse(jsonData));
however when running this I get the error: unexpected token 'i'.
I have tried to use stringily but then just outputs the entire sting again.
You don't need or want JSON for this, just build the object:
// Sample data
var elem = [{
value: "one"
}, {
value: "two"
}];
// Build the object
var obj = {
"DataObject": {
"user": {
"-name": "username"
},
"contentFile": {
"-filename": "Breaking_News",
"lock": {
"-fileIsBeingEdited": "false"
},
"content": {
"line": []
}
}
}
};
var line = obj.DataObject.contentFile.content.line;
elem.forEach(function(entry, index) {
if (entry.value != '') {
line.push({
"-index": index,
"-text": entry.value
});
}
});
// Show result:
document.body.innerHTML =
"<pre>" +
JSON.stringify(obj, null, 2) +
"</pre>";
Side note: You don't check for blank strings like this:
if (!entry.value == '') { // <== Incorrect
You can use:
if (entry.value != '') {
or:
if (entry.value) {
You shouldn't build JSON like this, but use JSON.stringify() (see MDN doc) instead:
var myObject={foo:"bar"};
var myJSON=JSON.stringify(myObject);
console.log(myJSON); //echo {"foo":"bar"}
Here is an alternative way:
var json = {
iceteaDataObject: {
"-name": "hindsc52"
},
contentFile: {
"-filename": "Ticker",
lock: { "-fileIsBeingEdited": "false" },
content: {line: []}
}
}
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
json.contentFile.content.line.push({"-index": i,"-text": elem[i].value }
}
}
var jsonStr = JSON.stringify(json);
You need to put all your keys in quotes for this to work. As the others have pointed out though, you are not really supposed to do this.
If you still want to do it your way, try this:
var jsonStr = '{'
+ '"iceteaDataObject": {'
+ '"user": {"-name": "hindsc52"},'
+ '"contentFile": {'
+ '"-filename": "Ticker",'
+ '"lock": { "-fileIsBeingEdited": "false" },'
+ '"content": {'
+ '"line": ['
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
jsonStr += '{'
jsonStr += '"-index": ' + i + ',';
jsonStr += '"-text": ' + '"' + elem[i].value + '"';
jsonStr += '},'
}
}
jsonStr += ']}}}}';

Categories

Resources