Jquery displaying items in nested loop - javascript

I would like to display items belonging to different customers. To this effect, i am fetching data through an ajax call and therefater grouping the data based on each unique customer. I then append the grouped data to my html.
Structure of my grouped data looks like:
"John Doe": [
{
"Item_id" : 1
"Item_name": "abc"
},
{
"Item_id" : 2
"Item_name": "def"
},
],
"Jane Doe":
{
"Item_id" : 3
"Item_name": "ghi"
},
{
"Item_id" : 4
"Item_name": "jkl"
},
]
My code looks like:
$.each(groupedData, function (key, value) {
$('.cust_items').append(`
<h4 class="mb-0"> ` + key + `</h4>
<table id="dataTable">
<thead>
<th>Item No.</th>
<th>Item Name</th>
</thead>
<tbody></tbody>
</table>
`);
$.each(value, function (ky, val) {
$('#dataTable tbody').append(
`<tr>
<td>
` + ky + `
</td>
<td>
` + val.Item_name + `
</td>
</tr>
`);
});
});
I am facing an inssue whereby all items are being displayed under the first customer while the data is being displayed correctly under the second customer.

You're missing commas after the properties and Jane Doe property's objects aren't enclosed in []. Consider changing your groupedData object as the syntax isn't right.
Edit: Also adjusted the template string and accessing the table with dynamic id as well.
Sample:
let groupedData = {
"John Doe": [{
"Item_id": 1,
"Item_name": "abc"
},
{
"Item_id": 2,
"Item_name": "def"
}
],
"Jane Doe": [{
"Item_id": 3,
"Item_name": "ghi"
},
{
"Item_id": 4,
"Item_name": "jkl"
}
]
};
$.each(groupedData, function(key, value) {
$('.cust_items').append(`
<h4 class="mb-0">${key}</h4>
<table id="dataTable_${key.split(' ').join('_')}">
<thead>
<th>Item No.</th>
<th>Item Name</th>
</thead>
<tbody></tbody>
</table>
`);
$.each(value, function(ky, val) {
$(`#dataTable_${key.split(' ').join('_')} tbody`).append(
`<tr>
<td>
${ky}
</td>
<td>
${val.Item_name}
</td>
</tr>
`);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cust_items">
</div>

I'm a bit late to the party, but here's a fun and practical way to display your data dynamically using the <template> element and vanilla JS.
The in-code comments should make clear how it works.
Note: Be wary of adding the id attribute to elements inside a template (or inside a loop for that matter) cuz duplicate id values are bad.
const data = {
"John Doe" :
[
{ "Item_id" : 1, "Item_name": "abc" },
{ "Item_id" : 2, "Item_name": "def" }
],
"Jane Doe" : [
{ "Item_id" : 3, "Item_name": "ghi" },
{ "Item_id" : 4, "Item_name": "jkl" }
]
};
// Identifies HTML elements and an array of the names
const
container = document.getElementsByClassName("cust_items")[0],
template = document.getElementById("group_template"),
names = Object.keys(data);
// Loops through the names and adds a new copy of the template's contents for each one
for (let name of names){
// Identifies HTML elements (Technically, some are `document fragments`)
const
copyOfTemplate = document.importNode(template.content, true),
header = copyOfTemplate.querySelector(".header"),
tbody = copyOfTemplate.querySelector("tbody");
// Sets the header for the new copy of the template's contents
header.innerHTML = name;
// Loops through the items for this name and makes a new row for each one
for(let item of data[name]){
// Identifies strings and new HTML elements
const
itemId = item["Item_id"],
itemName = item["Item_name"],
row = document.createElement("TR"),
idCell = document.createElement("TD"),
nameCell = document.createElement("TD");
// Sets the item number and item name in their respective cells
idCell.innerHTML = itemId;
nameCell.innerHTML = itemName;
// Adds the cells to the new row
row.appendChild(idCell);
row.appendChild(nameCell);
// Adds the new row to the `tbody` within the new copy of the template's contents
tbody.appendChild(row);
}
// The new copy is ready to go live -- adds it to the page
container.appendChild(copyOfTemplate);
}
.header{ font-size: 1.2em; margin-bottom: 0.3em; }
table{ margin-left: 0.3em; margin-top: 0; border-collapse: collapse; }
th, td{ padding: 0.3em 0.5em; }
<div class="cust_items"></div>
<template id="group_template">
<h4 class="header"></h4>
<table>
<thead>
<th>Item No.</th>
<th>Item Name</th>
</thead>
<tbody></tbody>
</table>
<hr />
</template>

Related

How to load Json array into separate table rows?

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

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 print result set associated in only one cell inside an html table

My db is composed two tables User and Friends
An User have many Friends
I need to show the following table view
I queried both tables with an INNER JOIN as follows
SELECT usr.FirstName, usr.Phone, usr.Email, fri.FirstName AS friendName
FROM User AS usr
INNER JOIN Friends AS fri
WHERE fri.idUser = usr.idUser
Because many Friends have an User, Friends have the control how many results set will be returned.
Output:
{
"FirstName" : "jose", "Phone" : 123, "Email": "jose#jose.com", "friendName" : "Pedro",
"FirstName" : "jose", "Phone" : 123, "Email": "jose#jose.com", "friendName" : "Juan", // Same user, with another friend
}
The result set is correct, but i don't achieve figure out how to print it like the table view shown previously from Javascript or any language programming code that requested that query
Any idea how to solve this ?
To elaborate, with HTML you can just use unordered lists <ul> for Friends column
<table border="1">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Phone</th>
<th>E-Mail</th>
<th>Friends</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Jose</td>
<td>123</td>
<td>jose#jose.com</td>
<td>
<ul>
<li>Pedro</li>
<li>Juan</li>
</ul>
</td>
</tr>
<tr>
<td>2</td>
<td>Felipe</td>
<td>456</td>
<td>felipe#felipe.com</td>
<td>
<ul>
<li>Carlos</li>
<li>Jose</li>
</ul>
</td>
</tr>
</tbody>
</table>
To use Javascript let's assume you have users array, you can loop on it and generate the <table> like this:
let users = [
{"userId": 1, "FirstName": "jose", "Phone": 123, "Email": "jose#jose.com", "friendName": "Pedro"},
{"userId": 1, "FirstName": "jose", "Phone": 123, "Email": "jose#jose.com", "friendName": "Juan"},
{"userId": 2, "FirstName": "felipe", "Phone": 456, "Email": "felipe#felipe.com", "friendName": "Carlos"},
{"userId": 2, "FirstName": "felipe", "Phone": 456, "Email": "felipe#felipe.com", "friendName": "Jose"}
];
// To combine friends of the same user in an array at property friendNames
let usersWithFriends = {};
for (let user of users) {
let index = 'user' + user.userId;
if (typeof usersWithFriends[index] === 'undefined') {
usersWithFriends[index] = user;
} else {
if (typeof usersWithFriends[index].friendNames === 'undefined') {
usersWithFriends[index].friendNames = [usersWithFriends[index].friendName];
delete usersWithFriends[index].friendName;
}
usersWithFriends[index].friendNames.push(user.friendName);
}
}
let tbodyHTML = '';
// For the # column
let no = 1;
for (let user in usersWithFriends) {
let userDetails;
if (usersWithFriends.hasOwnProperty(user)) {
userDetails = usersWithFriends[user];
}
tbodyHTML += '<tr>';
tbodyHTML += `<td>${no++}</td>`;
tbodyHTML += `<td>${userDetails.FirstName}</td>`;
tbodyHTML += `<td>${userDetails.Phone}</td>`;
tbodyHTML += `<td>${userDetails.Email}</td>`;
tbodyHTML += '<td><ul>';
for (let friendName of userDetails.friendNames) {
tbodyHTML += `<li>${friendName}</li>`;
}
tbodyHTML += '</td></ul>';
tbodyHTML += '</tr>';
}
document.getElementsByTagName('tbody')[0].innerHTML = tbodyHTML;
<table border="1">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Phone</th>
<th>E-Mail</th>
<th>Friends</th>
</tr>
</thead>
<tbody></tbody>
</table>
OK,I see the tag you mark this question as mysql, so it is very simple to implete the html output when use mysql command with a --html config. just like below:
mysql -u username -p password -D database --html -e"select * from your_table_name limit 10" > data_result.html
when you open the above html file data_result.html by browser, you'd get the print style you want.

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