How to load Json array into separate table rows? - javascript

I'm having trouble with displaying my json data correctly. I want to get each products and place them into it's own row.
The problem now is that it places all the data of for example the value "name" into one table row instead of multiple rows.
This is my json data
{
id: "FVFkkD7s8xNdDgh3zAyd",
name: "AlperKaffe",
products: [
{
id: "0cfBnXTijpJRu14DVfbI",
name: "Første Kaffe",
price: "1",
size: "small",
quantity: "20 ml"
},
{
id: "JQadhkpn0AJd0NRnnWUF",
name: "Anden Kaffe",
price: "2",
size: "Medium",
quantity: "25 ml"
},
{
id: "UwHHdH8bFxbVHkDryeGC",
name: "kaffeeen",
price: "300",
size: "Small",
quantity: "23 ml"
},
{
id: "WiX5h0wFMNkCux9cINYq",
name: "kaffe modal",
price: "230",
size: "Medium",
quantity: "39 ml"
},
this is my Js file which gets the json data. As you can see i'm only working with the "name" value for now
// Jquery getting our json order data from API
$.get("http://localhost:8888/products", (data) => {
let rows = data.map(item => {
let $clone = $('#frontpage_new_ordertable tfoot tr').clone();
let productsName = item.products.map(prod => `${prod.name}`);
$clone.find('.name').html(productsName);
return $clone;
});
// appends to our frontpage html
$("#frontpage_new_ordertable tbody").append(rows);
});
this is my html file
<body>
<table id="frontpage_new_ordertable">
<tbody>
<tr>
<th>Name</th>
<th>Price</th>
<th>Size</th>
<th>Quantity</th>
<th></th>
</tr>
</tbody>
<tfoot>
<tr>
<td class="name"></td>
<td class="price"></td>
<td class="size"></td>
<td class="quantity"></td>
<td class="buttons"></td>
</tr>
</tfoot>
</table>
<script src="./itemPage.js"></script>
</body>

you must replace
let rows = data.map(item => {
to
let rows = data.products.map(item => {
and
let productsName = item.products.map(prod => `${prod.name}`);
to
let productsName = item.name;
https://jsfiddle.net/ab7t1vmf/3/

The issue in your JS snippet seems to be let rows = data.map(item => { ...
From what you describe, the JSON data is comprised of 3 keys:
id
name
products
You cannot execute a map function directly on a Javascript Object, this function requires an array.
Looking a bit more at your code, I understand you need to display each product on its own row. Thus, you would need to use the map function on data.products which contains an array (of products).
let rows = data.products.map(item => {
// ...
$clone.find('.name').html(item.name);
// ...
// ...
});
Reference: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/map

Related

How to access multiple data elements of vue js in one tag of html file using v-for?

This is a part of my Vue project where I want to get some data elements in a table. I want to take data2 element like countryData in another column of the table. How can I do this? You can run the snippet for further reference.
In HTML code I have included the vue js library and simply made a table.
var app = new Vue({
el: "#app",
data(){
return {
countryData:[{name:"india", "1999":9537, "2000":10874},
{name:"china", "1999":7537, "2000":8874},
{name:"england", "1999":11537, "2000":12074}
],
data2: [
{ser1: 1, ser2: 7},
{ser1: 4, ser2: 1},
{ser1: 6, ser2: 8}
]}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<h3>Data Table</h3>
</div>
<table>
<thead>
<tr>
<th>Country</th>
<th>Sales</th>
</tr>
</thead>
<tbody>
<tr v-for="x in countryData">
<td>{{x.name}}</td>
<! -- I want to take data2 element in another column of my table -->
</tr>
</tbody>
</table>
</div>
You can either combine the data as you wish, before displaying in template, for example:
countryData: [
{ name: "india", "1999": 9537, "2000": 10874 },
{ name: "china", "1999": 7537, "2000": 8874 },
{ name: "england", "1999": 11537, "2000": 12074 }
],
data2: [{ ser1: 1, ser2: 7 }, { ser1: 4, ser2: 1 }, { ser1: 6, ser2: 8 }],
combinedData: []
// ...
created() {
this.countryData.forEach((x, i) => {
this.combinedData.push({ ...x, ...this.data2[i] });
});
}
Then you can access in template with:
<tr v-for="(x, i) in combinedData" :key="i">
<td>{{x.name}}</td>
<td>{{x.ser1}}</td>
<td>{{x.ser2}}</td>
</tr>
or you can utilize the index in the template:
<tr v-for="(x, i) in countryData" :key="i">
<td>{{x.name}}</td>
<td>{{data2[i].ser1}}</td>
<td>{{data2[i].ser2}}</td>
</tr>

how to give fixed table rows using typescript

I am using table for showing the datas and for data I am using Api.
Api data looks like::
{
"data": [
{
"id": "1",
"name": "name1",
"label": "label1"
},
{
"id": "2",
"name": "name2",
"label": "label2"
},
{
"id": "3",
"name": "name3",
"label": "label3"
}
]
}
html code
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Label</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of sample;">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.label}}</td>
<tr>
<tbody>
<table>
I need the 10 table rows statically(fixed). The table data is from API. For exanple ,Api contains 2 data... Then UI table should be with 2 rows of data and balance with emply rows... but there should display 10 rows(Mandatory)
which means in UI i want 10 rows with data from Api and balance should be empty.
You can fix in view layer, ts layer or even backend API layer (Not really recommended).
In view layer if you loop over your data, you can calculate if your data's size goes over arbitrary threshold and if not loop again to display as many empty rows as possible.
In ts layer, when you receive data from api you can modify variable you pass to your view by adding to an array as many empty items as you need.
What's important if you use null, then you have to check for it with for example elvis operator.
I would advise agains adding to an array an object with all properties set to null, because then these are not so easily distinguishable from valid data from API and you can for instance make some rows interactive, even though they should not be.
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
const viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
console.log(viewTableData)
Example in AngularJs (No Angular in SO Snippets, but it is the same principle)
angular.module('example', [])
.controller('ExampleController', function ExampleController() {
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
this.viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
});
table {
border-collapse: collapse;
}
td, th {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="example" ng-controller="ExampleController as example">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in example.viewTableData track by $index">
<td>{{row ? row.id : ' '}}</td>
<td>{{row ? row.name : ' '}}</td>
</tr>
</tbody>
</table>
</div>

fill table dynamically using GET request

an empty table. To fill the product table, its content should be created dynamically by using JavaScript to insert the data into the table. The data should be requested from the webserver. You should first send an AJAX GET request to the Web service. When this request returns successfully, you should insert the returned JSON data into your table using the DOM
You can try datatable plugin to fullfill your scenario
to work with this your data should be in the format of
{ "draw": 1, "recordsTotal": 57, "recordsFiltered": 57, "data": [
[
"Airi",
"Satou",
"Accountant",
"Tokyo",
"28th Nov 08",
"$162,700"
],
[
"Angelica",
"Ramos",
"Chief Executive Officer (CEO)",
"London",
"9th Oct 09",
"$1,200,000"
],
]
}
HTML CODE
<table id="example" class="display" style="width:100%">
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Position</th>
<th>Office</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<table>
JS CODE:
$(document).ready(function() {
$('#example').DataTable( {
"ajax": "../server_side/scripts/server_processing.php"
} );
} );
include below scripts too
https://code.jquery.com/jquery-3.3.1.js
https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js
You can append the dynamically created html using innserHTML property ofDOM element.
Example
fetch('<some URL>')
.then((response) => {
let data = response.json(); // Let supposed the data is in this format [{ id: 1 }, { id: 2 }, { id: 3 }]
let tr = '';
data.forEach(function(value) {
tr += `<tr><td>${data.id}</td></tr>`;
});
document.querySelector('#table_id tbody').innerHTML = tr; //Append the data
}).catch(error => {
console.log(error);
});
Or use document.createElement to create the element and then append it to the DOM
fetch('<some URL>')
.then((response) => {
let data = response.json(); // Let supposed the data is in this format [{ id: 1 }, { id: 2 }, { id: 3 }]
let tr = '';
let tableBody = document.querySelector('#table_id');
data.forEach(function(value) {
let tr = document.createElement('tr');
tr.textContent = data.id
tableBody.appendChild(tr);
});
}).catch(error => {
console.log(error);
});
HTML
<table id="table_id">
<tbody>
</tbody>
</table>

How to remove default order of ng-repeat

How do I stop default sorting inside the ng-repeat for dynamic table data ?
Currently I am getting below order:
Addr | CustomerId | Name
but what I want is below ordering:
CustomerId | Name | Addr
Any Help would me much appreciated.
JS:
app.controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
});
HTML:
<table>
<tr >
<th ng-repeat="(key,value) in Customers[0]">{{key}}</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
</tr>
</tbody>
</table>
Try this below way. I hope this below snippet result is showing what you want.
angular.module("aaa",[]).controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
$scope.keys = Object.keys($scope.Customers[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="aaa" ng-controller="MyController">
<table>
<tr>
<th ng-repeat="key in keys">
{{key}}
</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
<td ng-repeat="key in keys">{{c[key]}}</td>
</tr>
</tbody>
</table>
</div>
So objects in JS are inherently unordered. What you can do is just hard code the keys in the header if that will be fixed for that particular table and then print the values in the respective order.
Something like this:
<table>
<tr >
<th>CustomerId</th>
<th>Name</th>
<th>Addr</th>
</tr>
<tbody>
<tr ng-repeat="c in Customers">
<td>{{CustomerId}}</td>
<td>{{Name}}</td>
<td>{{c.Addr}}</td>
</tr>
</tbody>
</table>
Note: I put the ng-repeat on the tr which is probably what you need. I dont think you should put it on the tbody.
Do you mean the sort order of the data or the display order of the columns?
The accepted answer displays the data by the order of the columns as specified, but if you want the data itself sorted then just add a filter to the data like this:
<tbody ng-repeat="c in Customers|orderBy:['CustomerId','Name','Addr']">
This sorts the actual data in the list by the fields specified.

How can I associate a number to a specific string and use that string to filter an iteration in AngularJS?

I am new to AngularJS and I'm having problems doing a reusable generic filter.
Let's say I have a colors, types, and list objects as seen below (New JSON).
I want to make a generic filter that will take colors and types objects and filter the list object without having to use the string match as filter.
For now I did specific filters by strings as seen below.
I will have a lot of information in these objects and I don't want to update the controller each time a new property is being included in the JSON.
How do I associate the number to its specific string value?
Old JSON
[
{
"id": 1,
"name": "Spike",
"type": "dog",
"color": "gray"
},
{
"id": 2,
"name": "Tom",
"type": "cat",
"color": "blue"
},
{
"id": 3,
"name": "Butch",
"type": "cat",
"color": "black"
}
]
New JSONs
// colors
[
{"gray": 1},
{"black": 2},
{"blue": 3},
]
// types
[
{"dog": 1},
{"cat": 2}
]
// data list
[
{
"id": 1,
"type": 1,
"name": "Spike",
"color": 1
},
{
"id": 2,
"type": 2,
"name": "Tom",
"color": 3
},
{
"id": 3,
"type": 2,
"name": "Butch",
"color": 2
}
]
Filters
<table class="table table-bordered table-condensed table-striped table-hover">
<thead>
<tr>
<th>
<a>
Filters:
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in typeItems">
<td>
<label class="check">
<input type="checkbox" ng-model="typeFilterItems[item.type]">{{item.type}}
</label>
</td>
</tr>
<tr ng-repeat="item in colorItems">
<td>
<label class="check">
<input type="checkbox" ng-model="colorFilterItems[item.color]">{{item.color}
</label>
</td>
</tr>
</tbody>
</table>
List
<table class="table table-bordered table-condensed table-striped table-hover header-fixed">
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Color</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr class="list" ng-repeat="item in animals | filter:typeFilter | filter:colorFilter">
<td>{{item.id}</td>
<td>{{item.type}}</td>
<td>{{item.color}}</td>
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
Controller
Animals.list().then(function (data) {
$scope.animals = data;
});
$scope.colorFilterItems = { 'black': true, 'gray': false, 'blue': false }; // doing this to have a predefined filter selection ... for now
$scope.colorItems = [{ name: 'black' }, { name: 'gray' }, { name: 'blue' }];
$scope.colorFilter = function (item) {
return $scope.colorFilterItems[item.color]
};
$scope.typeFilterItems = { 'dog': true, 'cat': false }; // doing this to have a predefined filter selection ... for now
$scope.typeItems = [{ name: 'black' }, { name: 'gray' }, { name: 'blue' }];
$scope.typeFilter = function (item) {
return $scope.typeFilterItems[item.type]
};
Since no one answered I eventually found a solution.
The answer to all this is to use lodash directly inside the service and create a filter method inside the promise that looks for the selected property inside the filter objects and compares them to the data we want to display.
filterAnimals = () => {
intersectedResults =
_.filter(animals,(animal: iAnimal) => {
var colors = _.find(colorLabels,(item: iFilter) => {
return (animal.color ? item.label === animal.color : item.label == null) && item.selected;
});
var types = _.find(typeLabels,(item: iFilter) => {
return (animal.type ? item.label === animal.type : item.label == null) && item.selected;
});
return colors && types;
});
return data;
};
After doing this I acces the filterAnimals() function from the controller and bind the checkbox filters to my data. When doing an ng-change on the checkbox this function executes and checks the filters against the data and it shows the data I need.

Categories