Javascript map is not a function what trying to read data - javascript

I am trying to populate a chart so I'm getting the data into 2 lists in order to do this.
This is the data:
var data = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}];
And I am running this code in order to populate the lists:
var chList = [];
var boatList = [];
var boatCount = [];
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var cl = obj.name + " [" + obj.id + "]";
if (obj.boats != null) {
chList.push(cl);
}
if(obj.boats) {
var nme = obj.boats.map( function(item){
return item.name;
});
boatList = boatList.concat(nme);
boatCount.push(nme.length);
}
}
console.log(boatList);
console.log(boatCount);
My problem is that I keep getting:
TypeError: obj.boats.map is not a function
How can I fix this?
Note: The data is actually this:
{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
But I added [ and ] to it in order to use data.length and the lists where empty too ... Do I then leave this data as it is?

The problem is that obj.boats is an object, not an array, hence doesn't have the map method.
Try this instead:
Object.keys(obj.boats).map(function(k) { return obj.boats[k].name; });
See MDN

boats is an object, not an array. Map is for arrays.
You could use a for ( in ) loop or Object.keys() to get an array of keys and work with that.

The two other answers are right, I'd change the data though:
"boats": [
{
"id": "637",
"name": " Subcat 1",
"translations": null
},
{
"id": "638",
"name": "Subcat 2",
"translations": null
}
],
Using the id as key and then giving the containing object a "id" property is kinda pointless. When you change the data to this structure your code will work fine.

Besides all other answers that already correctly point to obj.boats being an Object and not an Array, I'd like providing a solution that demonstrates the elegant beauty of Array.reduce ...
var boatChartData = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}, {
"id": "623",
"name": "other name",
"boats": {
"639": {
"id": "639",
"name": "Supercat",
"translations": null
},
"640": {
"id": "640",
"name": "Supercat II",
"translations": null
},
"641": {
"id": "641",
"name": "Supercat III",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6295c"
}];
function collectBoatChartData(collector, chartItem/*, idx, list*/) {
var
boatNameList,
boatMap = chartItem.boats;
if (boatMap != null) {
collector.chartItemTitleList.push([
chartItem.name,
" [",
chartItem.id,
"]"
].join(""));
boatNameList = Object.keys(boatMap).map(collector.getBoatNameByKey, boatMap);
collector.boatNameList = collector.boatNameList.concat(boatNameList);
//collector.chartItemBoatNameList.push(boatNameList);
collector.chartItemBoatCountList.push(boatNameList.length);
}
return collector;
}
var processedBoatChartData = boatChartData.reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
console.log("processedBoatChartData.boatNameList : ", processedBoatChartData.boatNameList);
console.log("processedBoatChartData.chartItemTitleList : ", processedBoatChartData.chartItemTitleList);
//console.log("processedBoatChartData.chartItemBoatNameList : ", processedBoatChartData.chartItemBoatNameList);
console.log("processedBoatChartData.chartItemBoatCountList : ", processedBoatChartData.chartItemBoatCountList);
Note
Taking into account the OP's additional comment, mentioning the provided axample's real data structure, the above provided solution of mine just changes to ...
var boatChartData = {
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
var processedBoatChartData = [boatChartData].reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
.., proving that generic solutions can be recycled/adapted easily, if e.g. data structures do change.

Related

Grouping a multilevel array of objects

I am trying to learn javascript reduce and map an I came across some difficulties.
I have an array with the following format. The id of the parent is same as the location_id of the child. I need to group the array into a nested format.
arr = [
{
"id": 4583211,
"name": "Location 1",
"location_id": null,
},
{
"id": 7458894,
"name": "Location 12",
"location_id": 4583211
},
{
"id": 7463953,
"name": "Location 13",
"location_id": 4583211
},
{
"id": 80302210,
"name": "Location 121",
"location_id": 7458894
},
{
"id": 80302219,
"name": "Location 122",
"location_id": 7458894
},
{
"id": 7464314,
"name": "Location 131",
"location_id": 7463953
},
{
"id": 4583216,
"name": "Location 2",
"location_id": null,
},
{
"id": 3566353,
"name": "Location 21",
"location_id": 4583216
},
]
This array should be grouped as:
result = [
{
"id": 4583211,
"name": "Location 1",
"locations": [
{
"id": 7458894,
"name": "Location 12",
"locations": [
{
"id": 80302210,
"name": "Location 121"
},
{
"id": 80302219,
"name": "Location 122"
}
]
},
{
"id": 7463953,
"name": "Location 13",
"locations": [
{
"id": 7464314,
"name": "Location 131"
}
]
}
]
},
{
"id": 4583216,
"name": "Location 2",
"locations": [
{
"id": 3566353,
"name": "Location 21"
}
]
}
]
I tried to group it using the following method found on SO but it gives different result.
result = arr.reduce(function (r, a) {
r[a.location_id] = r[a.location_id] || [];
r[a.location_id].push(a);
return r;
}, Object.create(null));
You could do this using reduce and recursion you just need to check if parent is equal to current elements location_id.
const data = [{"id":4583211,"name":"Location 1","location_id":null},{"id":7458894,"name":"Location 12","location_id":4583211},{"id":7463953,"name":"Location 13","location_id":4583211},{"id":80302210,"name":"Location 121","location_id":7458894},{"id":80302219,"name":"Location 122","location_id":7458894},{"id":7464314,"name":"Location 131","location_id":7463953},{"id":4583216,"name":"Location 2","location_id":null},{"id":3566353,"name":"Location 21","location_id":4583216}]
function create(data, parent = null) {
return data.reduce((r, e) => {
if(parent == e.location_id) {
const o = { id: e.id, name: e.name }
const children = create(data, e.id);
if(children.length) o.locations = children;
r.push(o)
}
return r
}, [])
}
console.log(create(data))

Tableau Web Data Connector error

I am creating a Tableau Web Data Connector as per the documentation HERE.
I am running the Simulator and have setup a HTML page (as per tutorial) which calls a Javascript file that runs the Tableau WDC script as below.
(function () {
var myConnector = tableau.makeConnector();
myConnector.init = function(initCallback) {
initCallback();
tableau.submit();
};
myConnector.getSchema = function (schemaCallback) {
var cols = [
{ id : "date_of_work", alias : "Date of Work", dataType: tableau.dataTypeEnum.date },
{ id : "supervisor", alias : "Supervisor", dataType: tableau.dataTypeEnum.string }
];
var tableInfo = {
id : "test",
alias : "test",
columns : cols
};
schemaCallback([tableInfo]);
};
myConnector.getData = function (table, doneCallback) {
$.getJSON("http://myDataCall.php", function(response) {
// ERROR HERE!
var resp = response.job.job_workflows; // Response
var parsedResp = JSON.parse(resp); // Parse the response
var tableData = []; // Temp array
// Iterate over the JSON object
for (var i = 0, len = resp.length; i < len; i++) {
tableData.push({
"date_of_work": parsedResp[i]['job_status'],
"supervisor": parsedResp[i]['job_workflow_1197927'],
});
}
table.appendRows(tableData);
doneCallback();
});
};
tableau.registerConnector(myConnector);
})();
When I run the script I get the error: The WDC reported an error:
Uncaught SyntaxError: Unexpected token o in JSON at position 1 stack:SyntaxError:
Unexpected token o in JSON at position 1 at JSON.parse () at Object.success
The (abbreviated) JSON that is being returned looks as follows:
{
"employee": {
"id": 23940,
},
"company": {
"id": 1059,
},
"job": {
"id": 13712707,
"job_status_logs": [{
"id": 17330391,
}],
"company": {
"id": 1059,
},
"created_by": {
"id": 23940,
},
"job_workflows": [{
"id": 1087689283,
"job_id": 13712707,
"employee_id": null,
"template_workflow_id": 1251218,
"name": "Date of work",
"action": "datepicker",
"optional": 0,
"action_values": "",
"action_value_entered": "2017-10-12",
"nested_workflow_id": 0,
}, {
"id": 1087689284,
"job_id": 13712707,
"employee_id": null,
"template_workflow_id": 1251219,
"name": "Supervisor",
"action": "list",
"optional": 0,
"action_values": "John Doe",
"action_value_entered": "John Doe",
"nested_workflow_id": 0,
}],
"job_fields": [{
"id": 50456098,
}],
"job_status_change_messages": [{
"id": 59957985}],
"job_assets":[]
}
}
I am trying to access the job.job_workflows.action_value_entered value but keep getting the error as above.
How can I fix this error?
There are a couple of issues here.
1) The JSON sent back from your server is invalid. Here is the valid version. I recommend using a site like https://jsonformatter.curiousconcept.com/ to validate your JSON.
{
"employee": {
"id": 23940
},
"company": {
"id": 1059
},
"job": {
"id": 13712707,
"job_status_logs": [{
"id": 17330391
}],
"company": {
"id": 1059
},
"created_by": {
"id": 23940
},
"job_workflows": [{
"id": 1087689283,
"job_id": 13712707,
"employee_id": null,
"template_workflow_id": 1251218,
"name": "Date of work",
"action": "datepicker",
"optional": 0,
"action_values": "",
"action_value_entered": "2017-10-12",
"nested_workflow_id": 0
}, {
"id": 1087689284,
"job_id": 13712707,
"employee_id": null,
"template_workflow_id": 1251219,
"name": "Supervisor",
"action": "list",
"optional": 0,
"action_values": "John Doe",
"action_value_entered": "John Doe",
"nested_workflow_id": 0
}],
"job_fields": [{
"id": 50456098
}],
"job_status_change_messages": [{
"id": 59957985}],
"job_assets":[]
}
}
2) jQuery's getJson method returns an object, so you don't need to parse it. You can just use the resp variable directly like so:
var resp = response.job.job_workflows; // Response
var tableData = []; // Temp array
// Iterate over the JSON object
for (var i = 0, len = resp.length; i < len; i++) {
tableData.push({
"date_of_work": resp[i]['job_status'],
"supervisor": resp[i]['job_workflow_1197927'],
});
}
table.appendRows(tableData);
doneCallback();
Fixing those two issues should unblock you. However, you'll want to think through what data you are sending back. The current values you are sending back do not exist in the JSON (i.e. resp[i]['job_workflow_1197927']).
Instead, you could do something like this: resp[1].job_id, which would give you the job_id of each job_workflow.

remove duplicate value existing object from multidimensional array object in javascript

This is my javascript array:
[{
"id": "44",
"name": "chathura"
}, {
"id": "45",
"name": "gayan"
}, {
"id": "48",
"name": "sunimal"
}, {
"id": "47",
"name": "chathura"
}, {
"id": "20",
"name": "yasith"
}, {
"id": "21",
"name": "thisaru"
}, {
"id": "42",
"name": "insaf"
}, {
"id": "63",
"name": "sunimal"
}, {
"id": "78",
"name": "yasith"
}, {
"id": "36",
"name": "thisaru"
}]
I want to remove duplicate name existing object element from this array and get the following:
[{
"id": "47",
"name": "chathura"
}, {
"id": "45",
"name": "gayan"
}, {
"id": "48",
"name": "sunimal"
}, {
"id ": "20",
"name ": "yasith "
}, {
"id ": "21 ",
"name ": "thisaru"
}, {
"id ": "42 ",
"name ": "insaf"
}]
How can I remove duplicates?
You can iterate through the array and use a hash table to filter any IDs that have already been used:
function getUniqueNames(nameObjects) {
var existingIds = { };
return nameObjects
.filter(function(nameObject) {
var id = nameObject.id;
var alreadyExists = existingIds[id];
existingIds[id] = true;
return alreadyExists;
});
I'm not sure about your use case, but it might make sense in your case just to convert the data into a Map. Maps work similar to a hash table, and will map each name to its ID. They enforce uniqueness by design:
var names = nameObjects
.reduce(function(map, nameObject) {
map.set(nameObject.id, nameObject.name);
return map;
}, new Map());
// Look up a name by ID
names.get(47);
// Do something for every name
names.forEach(function(name, key) {
console.info(name, 'has ID', key);
});
Maps are ES6 and you may need a polyfill for some browsers.
Try this worked solution, using push method :
JS :
var arr = {};
for ( var i=0; i < x.length; i++ )
arr[x[i]['name']] = x[i];
var result = new Array();
for ( var key in arr )
result.push(arr[key]);
That will return an array of objects result that contain a non duplicated objects.
Result :
[{
"id": "47",
"name": "chathura"
}, {
"id": "45",
"name": "gayan"
}, {
"id": "48",
"name": "sunimal"
}, {
"id ": "20",
"name ": "yasith "
}, {
"id ": "21 ",
"name ": "thisaru"
}, {
"id ": "42 ",
"name ": "insaf"
}]
Hope this will help.

Jquery : transform nested json object to another json object

In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)

How to display an array returned by a json object (foreach dojo)

I have a json file returned as a json object (which is an array of arrays)...below is the returned json object
{
"Info": {
"Contact": ".... ",
"title": "..."
},
"details": [
{
"ID": 1,
"Question": "User ID",
"Information": "",
}, {
"ID": 2,
"Question": "Name",
"Information": "",
}, {
"ID": 3,
"Question": "Age",
"Information": "",
}
],
"list": [
{
"No": 1,
"response": ""
}, {
"No": 2,
"response": ""
}
]
}
Now i want to display only details...the below array
"Details": [
{
"ID": 1,
"Question": "User ID",
"Information": "",
}, {
"ID": 2,
"Question": "Name",
"Information": "",
}, {
"ID": 3,
"Question": "Age",
"Information": "",
}
],
How do i do this?? please help..
Thanks in advance.
1) parse the JSON into a javascript object
var parsedJSON = JSON.parse(jsonData);
2) access the properties you want
var details = parsedJSON.details;
edit: You are parsing your javascript object back into JSON, why??
working jsfiddle
var output = "";
for(var i=0; i<json.details.length; i++) {
var detail = json.details[i];
output += detail.ID +", "+ detail.Question +", "+ detail.Information +"\n";
}
alert(output);

Categories

Resources