How to map an indexed array data source in DataTables - javascript

Say i have an array as the data source for DataTables, delivered through AJAX
{
"data": [
[
"https://stackoverflow.com/questions/ask",
"Tiger Nixon",
"System Architect",
"Edinburgh",
"5421",
"2011/04/25",
"$320,800"
]
]
}
I want to ignore the first cell and not output it as a column, so how can i map the indexed data to the columns? I have already tried this, but it gives an error:
$(document).ready(function() {
$('#example').DataTable( {
"ajax": "data/objects.txt",
"columns": [
{ "data": [1] },
{ "data": [2] },
{ "data": [3] },
{ "data": [4] },
{ "data": [5] },
{ "data": [6] }
]
} );
} );
Uncaught TypeError: Cannot read property 'mData' of undefined
I also tried to reference the indexes like this
"data": 1
Doesn't work either.
If the source was an Object with keys, referencing would work like this:
"columns": [
{ "data": "name" },
{ "data": "position" },
{ "data": "office" },
{ "data": "extn" },
{ "data": "start_date" },
{ "data": "salary" }
]

I managed to find a solution myself, this code will make the first cell invisible and display the other cells:
$(document).ready(function() {
$('#example').DataTable( {
"ajax": "data/objects.txt",
"columnDefs": [
{ "targets": [0], "visible": false },
{ "targets": '_all', "visible": true }
]
} );
} );

var obj = {}
var keys = ['name', 'job', 'location', 'number', 'date', 'salary']
var arr = [
'https://stackoverflow.com/questions/ask',
'Tiger Nixon',
'System Architect',
'Edinburgh',
'5421',
'2011/04/25',
'$120000'
]
.filter((item, i) => !!i)
.forEach((v, i) => obj[keys[i]] = v)
console.log(obj)

Related

Loop through complex JSON with JavaScript

guys i have the following JSON
"detailed_statistics": [
{
"internal_key": "CORR",
"divider_name": "Corrosion Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Internal",
"hex_colour": "#d0320e",
"value": "386"
},
{
"plain_naming": "External",
"hex_colour": "#0000ff",
"value": "504"
}
]
}
]
},
{
"internal_key": "MILL",
"divider_name": "Manufacturing Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Internal",
"hex_colour": "#d0320e",
"value": "737"
},
{
"plain_naming": "External",
"hex_colour": "#0000ff",
"value": "54"
}
]
}
]
},
{
"internal_key": "DENT",
"divider_name": "Dent Features",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "53"
}
]
}
]
},
{
"internal_key": "WELD_ANOM",
"divider_name": "Weld Anomalies",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "2"
}
]
}
]
},
{
"internal_key": "OANOM",
"divider_name": "Complex Anomalies Not Otherwise Classified",
"plots": [
{
"chart_title": "Feature Location on Wall",
"chart_type": "pie",
"radius": "50%",
"data": [
{
"plain_naming": "Unclassified",
"hex_colour": "#000000",
"value": "51"
}
]
}
]
}
]
what i want is to dig into the data [] and get lets say the value and store it into a separate array and from there i want to pass it to a pie chart as a parameter in order to built a pie. the way i am doing it i get the response as below:
(7) ['386', '504', '737', '54', '53', '2', '51']
however what the response i want is :
(5) [['386', '504'],[ '737', '54'], '53', '2', '51']
how i achieve the above result ? the first 2 values needs to be grouped together as the belong to the same "family" if that make sense. i want to use either forEach or for loop Javascript/ typescript
they way i am doing it and doesnt work for me is:
this.myData[0].detailed_statistics.forEach(value => {
console.log("this is the value", value.plots)
value.plots.forEach(val => {
console.log("is this the titles?", val.chart_title)
this.plotTitles.push(val.chart_title)
this.plotRadius.push(val.radius)
val.data.forEach(plt => {
this.plotPlainName.push(plt.plain_naming)
this.plotValue.push(plt.value)
this.plotColor.push(plt.hex_colour)
})
});
})
You can do this to retrieve the values in the form that you want:
const result = this.myData[0].detailed_statistics
.map(stat => stat.plots
.map(plot => plot.data
.map(data => data.value)
)
)
.flat()
.map(values => values.length === 1
? values[0]
: values
)
If you want to stick with something similar to what you have, but where the plotPlainName, plotValue and plotColor arrays all follow the requested format, then you could do something like this:
this.myData[0].detailed_statistics.forEach(stat => {
stat.plots.forEach(plot => {
this.plotTitles.push(plot.chart_title)
this.plotRadius.push(plot.radius)
this.plotPlainName.push(
plot.data.length === 1
? plot.data[0].plain_naming
: plot.data.map(data => data.plain_naming)
)
this.plotValue.push(
plot.data.length === 1
? plot.data[0].value
: plot.data.map(data => data.value)
)
this.plotColor.push(
plot.data.length === 1
? plot.data[0].hex_colour
: plot.data.map(data => data.hex_colour)
)
})
})

Reading arrays within arrays of a json file

I am building a site which will output data from a JSON file into a table, but I am having issues getting the content to output. This JSON file is generated from another site which surfaces documentation, while my site just creates a table for easy searching of those docs.
SAMPLE JSON for 2 docs:
[{
"title": "SampleTitleA",
"lang": "en-US",
"lastEdition": "2020-07-28",
"version": "1.0",
"metadata": [
{
"key": "sampleKeyA1",
"label": "sampleLabelA1",
"values": ["sampleValueA1"]
},
{
"key": "sampleKeyA2",
"label": "sampleLabelA2",
"values": ["sampleValueA2"]
}]
},
{
"title": "SampleTitleB",
"lang": "en-US",
"lastEdition": "2020-07-28",
"version": "1.0",
"metadata": [
{
"key": "sampleKeyB1",
"label": "sampleLabelB1",
"values": ["sampleValueB1"]
},
{
"key": "sampleKeyB2",
"label": "sampleLabelB2",
"values": ["sampleValueB2"]
}]
}]
I am using DataTables for this (https://datatables.net/examples/ajax/deep.html) and have tried doing what it describes. It doesnt really cover reading arrays within arrays though.
To select an array within an array I have tried to follow the datatables example and done the following:
$(document).ready(function() {
$('#example').DataTable({
//sort on col 3 desc
"order": [3, 'desc'], //order by date
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
"ajax": {
"type": 'GET',
"dataType": 'json',
"lengthChange": true,
"contentType": 'application/json; charset=utf-8',
"url": "jsonlocation",
"deferRender": true,
"dataSrc": ""
},
"buttons": [ 'copy', 'excel',
{ extend: 'colvis', columns: [0,1,2,3,4,5,6]}
],
"dom": 'Bfrtip',
"columns": [
{ data: 'metadata.15.values.0', "defaultContent": "-" },
{ data: 'title', "defaultContent": "-" },
{ data: 'metadata.16.values.0', "defaultContent": "-" },
{ data: 'lastEdition', "defaultContent": "-" },
{ data: 'lang', "defaultContent": "-" },
{ data: 'version', "defaultContent": "-" },
{ data: 'readerUrl', "defaultContent": "-" },
{ data: 'readerUrl', "defaultContent": "-" },
],
"columnDefs": [{
"targets": [5],
"render": function(data, type, row, meta) {
return 'Click';
}
},
{
"targets": [7],
"visible": false,
"searchable": true
}
]
});
}
);
A table is created, but not populated, and shows no errors in console.
Has anyone any experience using dataTables for this purpose?
Thanks
Check if this helps you out.
var data = {
"title": "SampleTitle",
"lang": "en-US",
"lastEdition": "2020-07-28",
"version": "1.0",
"metadata": [
{
"key": "sampleKey1",
"label": "sampleLabel1",
"values": ["sampleValue1"]
},
{
"key": "sampleKey2",
"label": "sampleLabel2",
"values": ["sampleValue2"]
}]
}
var result = { data: data.metadata[1].values[0], "defaultContent": "-" }
console.log(result);
Your JSON data structure is an array - everything is contained in a [...] - therefore DataTables can iterate over this array to generate its table rows.
Here is an example with everything removed from your code except for the column data definitions (and column titles):
<script type="text/javascript">
$(document).ready(function() {
$('#example').DataTable({
ajax: {
// my test URL:
url: 'http://localhost:7000/sample2',
dataSrc: ''
},
"columns": [
{ title: 'Title', data: 'title' },
{ title: 'Language', data: 'lang' },
{ title: 'Key', data: 'metadata[0].key' },
{ title: 'Label', data: 'metadata[0].label' },
{ title: 'First Value', data: 'metadata[0].values[0]' }
]
} );
} );
</script>
This generates a table which looks like this:
How does this work?
By default, DataTables expects the JSON structure to be as one of the following:
An object containing an array of other objects:
{ "data": [ {...},{...},... ] }
An object containing an array of arrays:
{ "data": [ [...],[...],... ] }
In both these cases, the array has a name (in this case data).
In your case, as already noted, your data is just a plain array of objects:
[ {...}, {...},... ]
Because the array has no name, we need to use dataSrc: '' in our DataTable definition, to indicate this lack of a name.
After that, you can reference the values you need to display, for example data: 'title'.
For the metadata section, that is itself a label referring to an array of objects:
"metadata": [ {...} ]
However, in this case the array only contains one object. We can refer to that first object in the metadata array using [0] - and then we can access the values in that object - for example, by using: data: 'metadata[0].label'.

JS How to remove an object from array in a forEach loop?

I have a data object with following contents:
{
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "yellow",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
}
I want to remove block that has key yellow, by looping over blocks, rest of the data should be preserved as is. So expected end result would be
{
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
}
Data is dynamic so I dont know what would be returned, it might have a match for my condition or it might not.
I've tried a bunch of approaches but nothing seems to have worked so far. I can use lodash too if its any easier. None of those seems to be working. Any help/direction is appreciated
1. Using **delete**
const deleteUnwantedBlock = contentObj => {
const updatedData = contentObj;
const blocks = _.get(updatedData, 'blocks', []);
blocks.forEach(block => {
if (block.key.includes('yellow')) {
delete updatedData.block;
}
});
return updatedData;
};
console.log(deleteUnwantedBlock(data.content));```
2. Using rest operator:
const deleteUnwantedBlock = contentObj => {
const blocks = _.get(contentObj, 'blocks', []);
blocks.forEach(block => {
if (block.key.includes('yellow')) {
let { block, ...restOfTheData } = updatedData;
}
return { ...updatedEntry };
});
};
console.log(deleteUnwantedBlock(data.content));
You just need to filter:
const obj = {
"content": {
"id": "someID",
"type": "unit",
"method": "xyz",
"blocks": [{
"key": "blue",
"data": [
"Array"
]
}, {
"key": "red",
"data": [
"Array"
]
}, {
"key": "yellow",
"data": [
"Array"
]
}, {
"key": "black",
"data": [
"Array"
]
}],
"notes": "abc"
}
};
obj.content.blocks = obj.content.blocks.filter(({ key }) => key !== 'yellow');
console.log(obj);

How to sort a nested array using lodash

I have a collection of objects in this array and I need to order them by the 'order' key (asc). Is there a way to sort the objects inside the array and then return the whole array? I am relying on the order as I'm using it in a v-for with a :key.
[
{
"id":0,
"type":"Header",
"order":1,
"props":{
"order":0,
"id":0,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
},
{
"id":1,
"type":"Header",
"order":0,
"props":{
"order":1,
"id":1,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
}
],
[
//Another collection of objects
]
I am currently doing this -
getters: {
sorted: state => {
return _.orderBy(state.experience_sections, function(block) {
if(block.experience_blocks[0]) {
return block.experience_blocks[0].order;
}
});
}
}
The solution above does not seem to order the objects by 'asc' order. Am I on the right track?
Thanks!
P.S. Stack is telling me that is a possible duplicate question but I'm at a loss after hours of searching. My apologies if I missed an already answered question.
Just in case you want plain javascript solution.. using Array.forEach
I have also extended your array to contain more data
var arr = [[
{
"id":0,
"type":"Header",
"order":1,
"props":{
"order":0,
"id":0,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
},
{
"id":1,
"type":"Header",
"order":0,
"props":{
"order":1,
"id":1,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
}
], [
{
"id":0,
"type":"Header",
"order":2,
"props":{
"order":0,
"id":0,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
},
{
"id":1,
"type":"Header",
"order":1,
"props":{
"order":1,
"id":1,
"section_id":0
},
"data":{
"header":""
},
"component":"header-block"
}
]]
arr.forEach(d => d.sort((a,b) => a.order - b.order))
console.log(arr)
You should also consider orderBy method from lodash since you could easily change from asc to desc sort order if you would want to at a later date or have it via a variable being passed through the UI etc:
const data = [ [{ "id": 0, "type": "Header", "order": 1, "props": { "order": 0, "id": 0, "section_id": 0 }, "data": { "header": "" }, "component": "header-block" }, { "id": 1, "type": "Header", "order": 0, "props": { "order": 1, "id": 1, "section_id": 0 }, "data": { "header": "" }, "component": "header-block" } ], [{ "id": 0, "type": "Header", "order": 2, "props": { "order": 0, "id": 0, "section_id": 0 }, "data": { "header": "" }, "component": "header-block" }, { "id": 1, "type": "Header", "order": 1, "props": { "order": 1, "id": 1, "section_id": 0 }, "data": { "header": "" }, "component": "header-block" } ] ]
console.log('asc:', _.map(data, x => _.orderBy(x, 'order'))) // asc order
console.log('desc:', _.map(data, x => _.orderBy(x, 'order', 'desc'))) // desc
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Will sort each subarray in an array
const sortedArr = _.map(arr, subArray => _.sortBy(subArray, "order"));
Deep sorting using lodash
const sortedArray = _.orderBy(items, [(item) => {
const nestedObj = _.get(item, 'props');
item['props'] = _.orderBy(nestedObj,'order','desc');
return item['order'];
}], 'desc');

Two targets for the same column datatable

I have a datatable with json ajax.
But, i need to pass for the same column two targets. How i do that?
"columns": [
{ "data": "tpPedido" },
{ "data": "os" },
{ "data": "userMobile.nome" },
{ "data": "produto.nmProduto" },
{ "data": "status.NmStatus" },
{ "data": "produto.garantia.descricao" },
{ "data": "valor" },
{ "data": "valoradiantado" },
{ "data": "idPedidoAssistencia" },
{ "data": "idPedidoAssistencia" }
],
And the columndefs i trying to do this:
{ "render": function ( data, type, row ) {
return '<a onclick="relatorioAcerto('+data+')">R$: ' + parseFloat(data).toFixed(2).replace('.', ',').replace(/(\d)(?=(\d{3})+\,)/g, "$1." + '</a>');
}, "targets": 6,9},
You can define directly in columns array. render function accept three parameters. The last parameter holds entire data object.
"columns": [
{ "data": "tpPedido" },
{ "data": "os" },
{ "data": "userMobile.nome" },
{ "data": "produto.nmProduto" },
{ "data": "status.NmStatus" },
{ "data": "produto.garantia.descricao" },
{
"data": null,
"render" : function (data, type, row) {
return '<a href="'+row.idPedidoAssistencia+'" >Click here</a>';
}
},
{ "data": "valoradiantado" },
{ "data": "idPedidoAssistencia" },
{
"data": null,
"render" : function (data, type, row) {
return '<a href="'+row.idPedidoAssistencia+'" >Click here</a>';
}
}
],

Categories

Resources