I'm generating an HTML table from an array of objects. If the signature is on the left, I need to put it in the middle. In case I have two signatures, I need to leave them centralized, as they already are.
My current code:
var result = [
{name: "John",
jobPosition: "President"
},
{name: "Marc",
jobPosition: "Director"
},
{name: "Paul",
jobPosition: "Director"
},
{name: "Mary",
jobPosition: "Director"
},
{name: "Carl",
jobPosition: "Geral Secretary"
},
];
var table = '<table style=" height: 94px;" border="0" width="100%" cellspacing="0" cellpadding="0"><tbody>';
result.forEach(function(item, index) {
if (index % 2 == 0) {
table += '<tr style="height: 35px;">';
}
table += '<td style="width: 50%; height: 150px; text-align: center; font-family: arial; font-size: 12pt;" valign="top"><p>_____________________________</p><p>' + item.name + '</p><p>' + item.jobPosition + '</p></td>';
if (index % 2 == 1 || index == (result.length - 1)) {
table += '</tr>';
}
});
table += '</tbody></table>';
gs.info(table);
In this example,Carl's signature needs to come in the middle.
Example
Thanks in advance.
excuse me sir. now i found out your desire.
you should add colspan attribute to te last td if index % 2 == 1
and set the amount of this colspan to 2
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have a code in which I have three rows with three parameters $COKE, COKE, COKE.
Every row has a sublist which opens when I click the parameters. It works fine when parameter doesnt have any special characters i.e.
For case when $COKE is parameter it doesn't open sublist onclick. ($ dollar sign)
For case when COKE is parameter it opens sublist onclick.
For case when COKE. is parameter it doesn't open sublist onclick. (. dot sign)
data[i].parameter="$COKE"
document.getElementById("results").innerHTML += "<tr id="+data[i].parameter+" onclick='showSublist(this.id)'>
data[i].paramater can have values as shown below $COKE, COKE.,COKE as an example.
Image shown as reference, where only case 2 opens but case 1 and case 3 doesn't open when I click them.
Cases Image
By not escaping special characters you are creating invalid HTML code, that's why onclick doesn't work.
Here is example how browser handles special characters:
function escape(a) {
return "&#" + a.charCodeAt(0) + ";";
}
function escapeText(text) {
return text.replace(/["'&<>]/g, escape);
}
function showSublist(id) {
alert(id);
}
var data = [{
parameter: "test"
},
{
parameter: "$test"
},
{
parameter: "<test"
},
{
parameter: "test>"
},
{
parameter: "<test>"
},
{
parameter: '"test'
},
{
parameter: 'test"'
},
{
parameter: '"test"'
},
{
parameter: "test."
},
{
parameter: '&test'
},
{
parameter: '&test;'
},
{
parameter: "test${test}"
},
];
for (let i = 0, tr = document.createElement("tr"); i < data.length; i++) {
tr = tr.cloneNode(false);
tr.innerHTML = '<td class="n">' + i + '</td>';
/* original, incorrect structure */
tr.innerHTML += "<td id=" + data[i].parameter + " onclick='showSublist(this.id)'>" + data[i].parameter + '</td>';
tr.innerHTML += '<td class="n">' + i + '</td>';
/* correct structure, no filter */
tr.innerHTML += '<td id="' + data[i].parameter + '" onclick="showSublist(this.id)">' + data[i].parameter + '</td>';
tr.innerHTML += '<td class="n">' + i + '</td>';
/* correct structure, filter */
tr.innerHTML += '<td id="' + escapeText(data[i].parameter) + '" onclick="showSublist(this.id)">' + escapeText(data[i].parameter) + '</td>';
tr.onmouseover = mouseOver;
document.getElementById("results").appendChild(tr);
};
var div = document.getElementById("html");
function mouseOver(e) {
html.textContent = e.target.className == "n" ? e.target.nextSibling.outerHTML : e.target.outerHTML;
}
th {
text-align: start;
}
td:nth-child(even) {
border-right: 1em solid transparent;
}
td:hover {
background-color: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
div {
background-color: white;
color: black;
position: fixed;
bottom: 0;
margin-top: 1em;
padding: 0.5em;
border: 1px solid black;
}
table {
margin-bottom: 3em;
}
<table id="results">
<tr>
<th colspan="2">
Original, no quotes
</th>
<th colspan="2">
Unescaped
</th>
<th colspan="2">
Escaped
</th>
</tr>
</table>
<div id="html"></div>
In this I am trying to sort the data by partNo and it is perfectly sorted with this, but my problem is that the first column of the table does not sort with the rest of the columns. sr No has to be sorted with all other columns
here sr No is a key which is not sorted with other columns
let productDetails = {
"10": [{
id: "1",
partNo: "100",
productName: "bag",
size: "30",
color: ["Blue"],
description: "sky bags ",
}],
"20": [{
id: "2",
partNo: "15",
productName: "bottle",
size: "10",
color: ["Green", "Orange"],
description: "plastic and still",
}]
,
"30": [{
id: "4",
partNo: "25",
productName: "lunchbox",
size: "20",
color: ["Blue", "Red"],
description: "fresh food",
}],
"40": [{
id: "3",
partNo: "45",
productName: "pen",
size: "10",
color: ["Red", "Blue"],
description: "gel pen ",
}]
};
/**
* This function displays the data in the table
*/
function displayData() {
objectArray = Object.values(productDetails);
display(objectArray);
}
function display(productStore) {
messageTable(" ");
let table = "<table border = 1 cellpadding = 10 ><th colspan=7 >Product Details</th><tr><th>sr No</th><th>Product Id</th><th>Part No</th><th>Name</th><th>Size</th><th>Color</th><th>Description</th></tr>";
for (var key in productDetails) {
for (var weight in productDetails[key]) {
table += "<tr><td>" + key + "</td>";
table += "<td>" + productDetails[key][weight].id + "</td>";
table += "<td>" + productDetails[key][weight].partNo + "</td>";
table += "<td>" + productDetails[key][weight].productName + "</td>";
table += "<td>" + productDetails[key][weight].size + "</td>";
table += "<td>" + productDetails[key][weight].color + "</td>";
table += "<td>" + productDetails[key][weight].description + "</td>";
}
} messageTable(table);
}
/**
* function to sort an array by part No
*/
function sortByPartNo() {
let arr = [];
item = Object.keys(productDetails)
console.log(item)
item.forEach(function (index) {
productDetails[index].forEach(function (indexA) {
arr.push(indexA);
});
})
arr.sort(function (first, second) {
return parseFloat(first.partNo) - parseFloat(second.partNo);
});
console.log(arr)
printArray(arr, item)
}
/**
* function to print array in the table
*/
function printArray(arr, item) {
messageTable(" ");
let table = "<table border = 1 cellpadding = 10 ><th colspan=7 >Product Details</th><tr><th>sr No</th><th>Product Id</th><th>Part No</th><th>Name</th><th>Size</th><th>Color</th><th>Description</th></tr>";
for (let key in arr) {
table += "<tr><td>" + item[key] + "</td>";
table += "<td>" + arr[key].id + "</td>";
table += "<td>" + arr[key].partNo + "</td>";
table += "<td>" + arr[key].productName + "</td>";
table += "<td>" + arr[key].size + "</td>";
table += "<td>" + arr[key].color + "</td>";
table += "<td>" + arr[key].description + "</td>";
} messageTable(table);
}
/**
* function is to print the table
*/
function messageTable(data) {
document.getElementById("messageTableA").innerHTML = data;
}
/**
* this function is to print the message
*/
function message(message) {
document.getElementById("demo").innerHTML = message;
}
<!DOCTYPE html>
<html>
<head>
<style>
th,
td,
p,
input {
font-family: Arial, Helvetica, sans-serif;
}
table,
th,
td {
border: solid 1px #DDD;
border-collapse: collapse;
padding: 10px 10px;
text-align: center;
}
th {
font-weight: bold;
}
</style>
</head>
<body onload="displayData()">
<h2>Product Details:</h2>
<form action="">
<input type="button" value="sortByPartNo" onclick="sortByPartNo();">
<p id="result"></p>
<p id="demo"></p>
<p id="messageTableA"></p>
</form>
</body>
</html>
There's a couple ways to go about this, but the simplest would be to just construct a new objects from the original one that contains both the keys and values.
i.e. turn this:
{
"10": [{
"partNo": "100",
"size": "30",
// etc
}],
// ...
}
into this
[
{
"key": "10",
"partNo": "100",
"size": "30",
// etc
},
// ...
]
or alternatively, something like this works too. A similar approach is used in the concrete code example below.
[
{
"key": "10",
"value": {
"partNo": "100",
"size": "30",
// etc
},
},
// ...
]
Basically, we just need to bundle all the related information together before we do a sort(). After we sort, we can pass the bundled data as-is to your display functions, or we can separate them back into two lists, however you prefer.
A practical simplified example:
const data = {
1: {
color: 'blue',
size: 10,
},
2: {
color: 'green',
size: 50,
},
3: {
color: 'yellow',
size: 5,
},
}
// Object.entries() will reshape the data in a way that keeps keys and values together
// then we .sort() based on size
const sorted = (
Object.entries(data)
.sort((x, y) => x[1].size - y[1].size)
)
console.log('sorted keys and values', sorted)
// If you want, you can then split them back out into two separate array, like you had it:
console.log('sorted keys', sorted.map(x => x[0]))
console.log('sorted values', sorted.map(x => x[1]))
See this to learn about Object.entries, used in this particular example.
Scotty Jamison responded first and gave you a good description of options and alternatives. I urge you to accept his answer.
However, I figured I minus well provide my work that I had developed in response to your original question incorrectly marked as a duplicate (as you mention in the comments to your question here). It is a more fully worked out version of Scotty's first proposal, which places the outer key as a property inside the array entry.
// Just a convenience for building productDetails
let pdVal = (id,no,name,size,colors,desc) => ({
id: id,
partNo: no,
productName: name,
size: size,
color: colors,
description: desc
})
let productDetails = {
"10": [pdVal("1","100","bag","30",["Blue"],"sky bags ")],
"20": [pdVal("2","15","bottle","10",["Green", "Orange"],"plastic and still")],
"30": [pdVal("4","25","lunchbox","20",["Blue", "Red"],"fresh food")],
"40": [pdVal("3","45","pen","10",["Red", "Blue"],"gel pen ")]
};
function sortByPartNo() {
let arr = [];
for (let key of Object.keys(productDetails)) {
let obj = productDetails[key][0];
arr.push(Object.assign({}, obj, {key}));
}
arr.sort((a,b) => parseFloat(a.partNo) - parseFloat(b.partNo))
printArray(arr);
}
function printArray(arr) {
messageTable(" ");
let table = `
<table border = 1 cellpadding = 10 >
<th colspan=7 >Product Details</th>
<tr>
<th>sr No</th>
<th>Product Id</th>
<th>Part No</th>
<th>Name</th>
<th>Size</th>
<th>Color</th>
<th>Description</th>
</tr>
`;
for (let item of arr) {
console.log({arr})
table += "<tr><td>" + item.key + "</td>";
table += "<td>" + item.id + "</td>";
table += "<td>" + item.partNo + "</td>";
table += "<td>" + item.productName + "</td>";
table += "<td>" + item.size + "</td>";
table += "<td>" + item.color + "</td>";
table += "<td>" + item.description + "</td>";
}
messageTable(table);
}
function messageTable(data) {
document.getElementById("messageTableA").innerHTML = data;
}
<input type="button" value="sortByPartNo" onclick="sortByPartNo();">
<p id="result"></p>
<p id="demo"></p>
<p id="messageTableA"></p>
I am trying to use ngx-clipboard module in my angular application.
The data in the table is coming from a service and i am using jsonToTable() to insert a dynamic table.
component.ts
generateOverrideCode(){
try {
document.getElementById('tableGoesHere').innerHTML = this.jsonToTable(data, 'table table-sm table-dark');
}
catch (ex) {
console.log('--generate override code', ex);
}
}
capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
jsonToTable(json, classes){
var cols = Object.keys(json[0]);
var headerRow = '';
var bodyRows = '';
classes = classes || '';
cols.map((col)=>{
headerRow += '<th>' + this.capitalizeFirstLetter(col) + '</th>';
});
json.map((row)=> {
bodyRows += '<tr>';
cols.map((colName)=> {
if(colName != 'population')
bodyRows += '<td>' + row[colName] + '</td>';
else
bodyRows += '<td id="colName+row">' + row[colName] + '<button></button>' + '</td>'; //I want to add a dynamic id to the button added to each cell of this row, so that i can use the id to target the text of that cell.
});
bodyRows += '</tr>';
});
return '<table class="' +
classes +
'"><thead><tr>' +
headerRow +
'</tr></thead><tbody>' +
bodyRows +
'</tbody></table>';
}
}
var data = [
{ country: 'China', population: 1379510000 },
{ country: 'India', population: 1330780000 },
{ country: 'United States', population: 324788000 },
{ country: 'Indonesia', population: 260581000 },
{ country: 'Brazil', population: 206855000 },
];
component.html
<div class="row">
<div class="col-sm-12">
<button (click)="generateOverrideCode()">Generate</button>
</div>
</div>
<div id="tableGoesHere"></div>
What i am trying to achieve is adding a copy button next to the each cell in the third column.
I also want each cell to have a unique id so i can target it using ngx-clipboard directive. Follow link for example
https://maxisam.github.io/ngx-clipboard/
I have created a stackblitz example as well.
https://stackblitz.com/edit/angular-s5g1b5
Please help me with adding unique id to each cell then i will move to adding ngx-clipboard.(i have added comments in stackblitz where i attempted to add unique id)
I am trying to populate a table using a JSON file. When I run this through the browser, my first row populates. However the other rows do not. Can someone please point out to me what I am doing wrong? Am I not looping this correctly? Thank you in advance.
$(document).ready(function() {
$.getJSON( "data.json", function(data) {
var htmlToRender= [];
var item;
for (var i = 0; i < data.length; i++) {
item = data[i];
console.log(data[i]);
htmlToRender = '<tr><td>' + item.name + '</td>'
'<td>' + item.description + '</td>'
console.log(item.description)
'<td>Open In Google Mapspwd</td></tr>';
console.log(item.location);
$('#hot-spots').append(htmlToRender);
console.log(htmlToRender);
};
});
});
The lines following htmlToRender = '<tr><td>' + item.name + '</td>' look a bit suspicious--you're missing a + sign to concatenate these additional strings, and sprinkled console.logs amidst the string build isn't helping the cause.
I recommend using a string template:
const item = {
name: "hello",
description: "world",
location: "somewhere"
};
const htmlToRender = `
<tr>
<td>${item.name}</td>
<td>${item.description}</td>
<td>
Open In Google Maps
</td>
</tr>
`;
$('#hot-spots').append(htmlToRender);
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
padding: 0.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="hot-spots"></table>