I am trying to render a table based on JSON object that I get from an API. The simplified object looks like this:
{
"id": 1,
"enabled": true,
"headers": [
{
"id": 1,
"header_name": "LastName",
"colVal": { "id": 1, "value": "Hopper" }
},
{
"id": 2,
"header_name": "FirstName",
"colVal": { "id": 1, "value": "Grace" }
}
]
}
What I want to be able to do from this JSON object is create a table like this:
LastName
FirstName
Hopper
Grace
Also, this table could have more data in colVal, in this case the JSON will look like this
{
"id": 1,
"enabled": true,
"headers": [
{
"id": 1,
"header_name": "LastName",
"colVal": [
{ "id": 1, "value": "Hopper" },
{ "id": 3, "value": "Lovelace" }
]
},
{
"id": 2,
"header_name": "FirstName",
"colVal": [
{ "id": 2, "value": "Grace" },
{ "id": 4, "value": "Ada" }
]
}
]
}
And this would be rendered as follows:
LastName
FirstName
Hopper
Grace
Lovelace
Ada
So far I've managed to generalize it enough that I can get the table headers rendered properly but the col values are going to the correct columns, instead a new row is being created. Here is the code
<table v-if="apiResponseData.custom_field_table[0].enabled_ind == true">
<thead>
<tr>
<th
v-for="header in apiResponseData.custom_field_table[0].headers"
:key="header.id"
>
{{ header.header_name }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="headerVal in apiResponseData.custom_field_table">
<div v-for="col in headerVal.headers">
<td style="width: 1%; border: 1px solid; text-align: center">
{{ col.colVal[0].value }}
</td>
</div>
</tr>
</tbody>
</table>
While you could wrangle the template to be able to use the data in its current form, I think you might be better served by running the data through a computed, which will make it much simpler. The thing that complicates the template is that the data array goes in the "horizontal" direction first and the "vertical" second, this makes constructing the loop more complicated. If you transpoze your data, the template will be much simpler.
script:
const headers = computed(()=>{
return hdrData?.headers.map(h => ({header:h.header_name, id:h.id}))
})
const rows = computed(()=>{
let rowData = [];
hdrData?.headers.forEach(h => {
let key = h.header_name
h.colVal.forEach((r, i) => {
if(!rowData[i]) {rowData[i] = {id:i}}
rowData[i][key] = r.value
})
})
return rowData
})
template:
<table v-if="headers">
<thead>
<tr>
<th v-for="{header, id} in headers" :key="id">{{header}}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key={row.id}>
<div v-for="{title, id} in headers">
<td style="width: 1%; border: 1px solid; text-align: center">
{{ row[header] }}
</td>
</div>
</tr>
</tbody>
</table>
Related
Without creating a new helper and just use the existing one's from "handlebar-helpers"
So I am actually trying to add the values in the below specified payload.
{
"products": [
{
"product": [
{
"price": 10
},
{
"price": 20
},
{
"price": 30
}
]
},
{
"product": [
{
"price": 10
},
{
"price": 20
},
{
"price": 30
}
]
}
]
}
From the above payload. I am trying to compute the sum of products array based upon the index position of product array.
The output for this payload is 20 , 40 ,60 respectively.
I tried with pluck block as,
{{pluck products "products.price"}} but it simply didn't work.
Is there any workaround for this ?
Current logic that doesn't works.
{{#each products}}
{{#each product}}
{{sum (pluck products "product.price")}}
{{/each}}
{{/each}}
I am working with DataTables, trying to load my json data. The HTML renders fine but I can't get any data to display. The live data wasn't working so I created a string to simulate the return. I'm not making an Ajax call to get the data, I'm calling the endpoint in c# and passing the resulting json string to JS. I'm getting no errors in the console. If you are curious why I'm not using Ajax, I'll say I don't know. :-)
We just downloaded DataTables so it is the latest version and the project is .Net Framework 4.6.1
Here is my Json:
var fakeJson =
{
"data":
{
"Triggers": {
"TriggerTypeId": 2,
"TriggeredKeyId1": 499,
"TriggerHelpText": "Blah blah blah",
"TriggerActionDefinitionID": 2,
"ComparisonOperatorID": 1
},
"Action": {
"TaDescription":"this is an action description"
},
"Protocols": {
"protocolDescription": "this is a protocol description"
},
"Operators": {
"CODisplayText": "="
}
}
};
and here is my JS:
var dataSource = <%= DataTableJson %>;
dataString = JSON.stringify(dataSource);
dataSource = JSON.parse(dataString);
console.log(fakeJson.data.Triggers.TriggerHelpText);
var editor = new $.fn.dataTable.Editor({
table: '#ProtocolTriggerTable',
"data": fakeJson
},
fields: [{
label: "Comparison",
name: "data.Operators.CODisplayText",
//type: "select"
}, {
label: "Action",
name: "data.Action.TaDescription",
//type: "select"
}, {
label: "Item",
name: "data.Protocols.protocolDescription",
//type: "select"
}, {
label: "Pop-up Text",
name: "data.Triggers.TriggerHelpText",
//type: "select"
}]
});
$('#ProtocolTriggerTable').DataTable({
dom: "rt",
data: fakeJson,
columns: [
{ data: "data.Operators.CODisplayText" },
{ data: "data.Action.TaDescription" },
{ data: "data.Protocols.protocolDescription" },
{ data: "data.Triggers.TriggerHelpText" }
],
});
and the HTML
<table border="1" id="ProtocolTriggerTable" class="display" style="background-color: #e0e0e0; width:100%;">
<thead>
<tr>
<th style="width:20px !important"></th>
<th>Comparison</th>
<th>Action</th>
<th>Item</th>
<th>Pop-up Text</th>
</tr>
</thead>
</table>
Follow-up: Based on two or three good comments below, here is the Json structure that finally worked. No I just have to apply this to my live data.
var fakeJson =
[{
"Triggers": {
"TriggerTypeId": 2,
"TriggeredKeyId1": 499,
"TriggerHelpText": "Blah blah blah",
"TriggerActionDefinitionID": 2,
"ComparisonOperatorID": 1
},
"Action": {
"TaDescription": "this is an action description"
},
"Protocols": {
"protocolDescription": "this is a protocol description"
},
"Operators": {
"CODisplayText": "="
}
}];
The format of the DataTableJson is not usable try something like this:
[
['Comparison0', 'Action0', 'Item0', 'Popup0'],
['Comparison1', 'Action1', 'Item1', 'Popup1'],
]
Issue: With the current code, when i click an item, it correctly adds the "selected" class to the clicked item, but when i click another option, the "selected" class gets removed from it and gets added to the newly clicked item.
Wanted: I want to have the selected class added to all items which have been selected, my code is below, would appreciate any help:
My Html:
<form (ngSubmit)="onSubmit()">
<div *ngFor="let event of groupSelections; let i = index;" class="row">
<div class="col-12">
<div class="row">
<div *ngFor="let team of event?.Actors; first as isFirst" class="col-6">
<div class="row">
<div *ngIf="isFirst" class="col-6">
<div>
{{ team?.ActorName }}
</div>
</div>
<div class="col-6">
<div [className]="selectedValue == team?.Players ?'selected':''">
<select (change)="getSelections(team, event, $event, team?.Players)">
<option value="none" selected disabled hidden>SELECT</option>
<option value="" *ngFor="let player of team?.Players; let j = index">
{{ player?.Name }}
</option>
</select>
</div>
</div>
<div *ngIf="!isFirst" class="col-6">
<div>
{{ team?.ActorName }}
</div>
</div>
</div>
</div>
</div>
</div>
My function:
getSelections(actors, event, selectedOption, player): any {
const selections = [];
this.selectedTeam = actors;
this.selectedTeamPlayers = actors.Players;
this.gameEvent = event;
this.selectedValue = player;
selections.push({
EventId: this.gameEvent.EventId,
ActorId: this.selectedTeam.ActorId,
EventActorId: this.selectedTeam.EventActorId,
Score: 1,
Position: 1,
PlayerPosition: this.player.Position,
PlayerPoint: this.player.Point,
});
this.playerSelections = selections;
}
My Data:
groupSelections = [
{
"PromotionId": 5,
"Events": [
{
"Actors": [
{
"ActorId": 33,
"ActorName": "Italy",
"Players": [
{
"Name": " Mattia De Sciglio (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Bryan Cristante (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
},
{
"ActorId": 34,
"ActorName": "Turkey",
"Players": [
{
"Name": " Zeki Çelik (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Ozan Tufan (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
}
]
},
{
"Actors": [
{
"ActorId": 77,
"ActorName": "Slovakia",
"Players": [
{
"Name": "Mattia Perin (G)",
"Position": "GOALKEEPER",
"Point": 10
},
{
"Name": "Bryan Cristante (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
},
{
"ActorId": 78,
"ActorName": "Sweden",
"Players": [
{
"Name": " Zeki Çelik (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Ozan Tufan (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
}
]
}
]
}
Usually you should add a selected field to your Players object. Then you can set it to true and consider it when adding the additional class.
But let's do it with a simple array first.
TS file
selectedPlayers: Array<string> = [];
// check whether the players object is in the list
isSelectedPlayer(players: any): boolean {
return this.selectedPlayers.findIndex(element => element === players) > -1;
}
getSelections(actors, event, selectedOption, player): any {
const selections = [];
this.selectedTeam = actors;
this.selectedTeamPlayers = actors.Players;
this.gameEvent = event;
// add the selection to your list, if is not in it
if (this.selectedPlayers.findIndex(element => element === player) === -1) {
this.selectedPlayers.push(player);
}
selections.push({
EventId: this.gameEvent.EventId,
ActorId: this.selectedTeam.ActorId,
EventActorId: this.selectedTeam.EventActorId,
Score: 1,
Position: 1,
PlayerPosition: this.player.Position,
PlayerPoint: this.player.Point,
});
this.playerSelections = selections;
}
HTML
<div [className]="gameEvent == event && isSelectedPlayer(team?.Players) ? 'selected':''">
Im using an AJAX request to get the results from the controller to populate them in the datatable. The results are returned from the controller in JSON format but I keep getting the Uncaught TypeError: Cannot read property 'length' of undefined error.
Are there anymore datatable parameters I should set in the controller?
The controller class:
#RequestMapping(value = "/users/list", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public List<User> listOfUsers() {
List<User> usersList;
usersList = userService.getAllUsers();
return usersList;
}
Datatable UI in thymeleaf :
<div class="table-responsive">
<table id="usersTable" class="table table-bordered table-hover dataTable">
<thead>
<tr>
<th th:text="#{user.table.heading.username}">User Name</th>
<th th:text="#{systemUser.table.heading.firstname}">First Name</th>
<th th:text="#{systemUser.table.heading.lastname}">Last Name</th>
<th th:text="#{systemUser.table.heading.status}">Status</th>
<th th:text="#{systemUser.table.heading.role}">Role</th>
</tr>
</thead>
</table>
</div>
AJAX request :
<script th:inline="javascript">
$(document).ready(function () {
$('#usersTable').DataTable({
"processing": true,
dataType: 'json',
"ajax": {
"url": "http://localhost:8080/sample/users/list",
"type": "GET"
},
"columns": [
{"data": "username"},
{"data": "firstName"},
{"data": "lastName"},
{"data": "status"},
{"data": "roleName"}
]
})
});
</script>
The JSON response :
[
{
"id":1,
"username":"dinesh#example.com",
"firstName":dinesh,
"lastName":damian,
"password":"$2a$10dfgfdgfdgd6O.iO6XB5xcyEZuppAHWOZGwX8m8xCLqS",
"status":"ACTIVE",
"role":{
"id":1,
"roleName":"ADMIN",
"status":"ACTIVE",
"permissionList":[
{
"id":1,
"name":"ROLE_LOGIN",
"description":"User login permission",
"checked":false
}
],
"checkedPermissions":[
]
}
}
]
Usually Cannot read property ‘length’ of undefined means that DataTables cannot find the data in the response.
Use the following initialization options to match your response structure.
$('#usersTable').DataTable({
"processing": true,
dataType: 'json',
"ajax": {
"url": "http://localhost:8080/sample/users/list",
"type": "GET",
"dataSrc": ""
},
"columns": [
{"data": "username"},
{"data": "firstName"},
{"data": "lastName"},
{"data": "status"},
{"data": "role.roleName"}
]
});
See ajax.dataSrc for more information.
It was successfully rendered after changing the AJAX request into this.
<script th:inline="javascript">
$(document).ready(function () {
$('#usersTable').DataTable({
"sAjaxSource": "http://localhost:8080/sample/users/list",
"sAjaxDataProp": "",
"aoColumns": [
{"mData": "username"},
{"mData": "firstName"},
{"mData": "lastName"},
{"mData": "status"},
{"mData": "role.roleName"}
]
})
});
<script th:inline="javascript">
I need to know about to access Collection object data in html as shown below :
var fieldData = [
{fieldName: "Hcare1",
fieldOptions: [ "Bike","Car","TV","Radio","etc"]
},
{fieldName: "Hcare2",
fieldOptions: [ "Bike1","Car1","TV1","Radio1","etc"]
},
{fieldName: "Hcare3",
fieldOptions: [ "Bike2","Car2","TV2","Radio2","etc"]
}
];
In the above code how to access fieldOptions data in html.The fieldData is inserted into a collection i.e Collection name is Fields.I'm new to meteor.So can you please suggest me what to do?
In mongo console:
db.foo.findOne().fieldOptions;
[ "Bike", "Car", "TV", "Radio", "etc" ]
Or on client:
collectionName.findOne().fieldOptions;
In JS:
Template.your_layout.helpers({
fieldOptions: function() {
Fields.findOne().fieldOptions;
}
});
In HTML:
{{#each fieldOptions}}
{{this}}
{{/each}}
Smth like this...