Apologies for any simple mistakes, this is my first Stack Overflow post and I'm relatively new to coding.
I am attempting to create a website that displays a dynamically generated table using DOM elements. This table's rows and columns have been defined using DOM elements, and it should now populate itself on page load when storeItemOutput() is called from initialize(). It should be pulling the data from a loop through the previously defined and populated array storeItems, and displaying their attributes in the table id "storeItemOutput". It should also get one of five values from a dropdown box, and display items that match the selected category whenever it is changed.
However, I can't get the table itself or it's contents to actually display on the page. I'm unsure what is preventing this, and the lack of any output has left me stumped. Am I missing some code in my function? Is the table not created properly?
I've included parts of my code below, as well as expected output and actual output to try and help you understand my issue.
<select class="categoryDropDown" style="margin: 30px;">
<p>
<option selected value="All" onload="storeItemOutput();">All</option>
<option value="Tops" onchange="storeItemOutput();">Tops</option>
<option value="Bottoms" onchange="storeItemOutput();">Bottoms</option>
<option value="Shoes" onchange="storeItemOutput();">Shoes</option>
<option value="Accessories" onchange="storeItemOutput();">Accessories</option>
</p>
</select>
<table id="storeItemOutput">
<span><strong>| ID | Product Name | Price | Qty | Max | Category | Image |</strong></span>
</br>
<tbody>
<tr>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
</tr>
<tr>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
</tr>
</tbody>
(Output all store items via DOM table here)
</table>
This is some of my HTML code with an ID'd dummy table, and a dropdown menu class.
var storeItems = [];
function StoreItem(id, name, price, qtyOnHand, maxPerCust, category, shipping, reviews, description, image) {
this.id = id; //String
this.name = name; //String
this.price = price; //Number
this.qtyOnHand = qtyOnHand; //Number
this.maxPerCust = maxPerCust; //Number
this.category = category; //String
this.shipping = shipping; //Number
this.reviews = reviews; //Array
this.description = description; //String
this.image = image; //String
}
storeItems.push(new StoreItem("Y2k111", "Black Hoodie", 119.99, 10, 1, "Tops", 19.99, this.reviews, "100% Cotton Hoodie in Black", "/img/home_img/link"));
Some Javascript code of creating an empty array for store items, creating an object constructor for store items, and pushing a new item to the array (normally there is more than one item being pushed, I used just one here to save space).
function storeItemOutput() {
var itemTableDiv = document.getElementById("cartItemOutput");
var table = document.createElement("table");
itemTableDiv.innerHTML = "";
document.getElementsByTagName("tbody")[0].remove();
var tBody = document.createElement("tbody");
var headerRow = document.createElement("tr");
var hC1 = document.createElement("th");
var hC2 = document.createElement("th");
var hC3 = document.createElement("th");
var hC4 = document.createElement("th");
var hC5 = document.createElement("th");
var hC6 = document.createElement("th");
var hC7 = document.createElement("th");
hC1.innerHTML = "Item ID";
hC2.innerHTML = "Item Name";
hC3.innerHTML = "Item Price";
hC4.innerHTML = "Item Quantity";
hC5.innerHTML = "Max Items Per Customer";
hC6.innerHTML = "Category";
hC7.innerHTML = "Image";
headerRow.appendChild(hC1);
headerRow.appendChild(hC2);
headerRow.appendChild(hC3);
headerRow.appendChild(hC4);
headerRow.appendChild(hC5);
headerRow.appendChild(hC6);
headerRow.appendChild(hC7);
tbody.appendChild(headerRow);
for (var index = 0; index < storeItems.length; index++) {
var products = storeItems[i];
var theRow = document.createElement("tr");
var c1 = document.createElement("td");
var c2 = document.createElement("td");
var c3 = document.createElement("td");
var c4 = document.createElement("td");
var c5 = document.createElement("td");
var c6 = document.createElement("td");
var c7 = document.createElement("td");
c1.innerHTML = products.id;
c2.innerHTML = products.name;
c3.innerHTML = "$" + products.price.toFixed(2);
c4.innerHTML = products.qtyOnHand;
c5.innerHTML = products.maxPerCust;
c6.innerHTML = products.category;
c7.innerHTML = products.image;
theRow.appendChild(c1);
theRow.appendChild(c2);
theRow.appendChild(c3);
theRow.appendChild(c4);
theRow.appendChild(c5);
theRow.appendChild(c6);
theRow.appendChild(c7);
tbody.appendChild(theRow);
}
itemTableDiv.appendChild(tbody);
var selectedCategory = document.getElementByClass("categoryDropDown").value;
var filteredItems = [];
var index = 0;
while (index < storeItems.length) {
if (storeItems[index].category == selectedCategory) {
filteredItems.push(storeItems[index]);
}
index++;
}
storeItemOutput(filteredItems);
And finally, my function that is meant to create and populate the table, before displaying the items that match the selected category.
Here is an image of what the table should look like:
working table
And the lack of output for my table:
my missing table
Any help would be appreciated.
Here's a working example. A few things worthy of mention:
I've used a template element, since it makes repeatedly creating
similar content very much faster.
Floating-point math has rounding errors. For this reason, I've stored the
prices in cents rather than dollars. Perform all math on the number
of cents, then present it as dollars & cents
A NodeList is very similar to, but slightly different than an array. It does not for instance have a forEach member function. For this reason, I used Array.from in the appendRow function. (which is actually shorter by 1 line if you use the commented code instead)
"use strict";
function newEl(tag) {
return document.createElement(tag)
}
function byId(id) {
return document.getElementById(id)
}
function qs(sel, parent = document) {
return parent.querySelector(sel)
}
function qsa(sel, parent = document) {
return parent.querySelectorAll(sel)
}
window.addEventListener('load', onLoaded, false);
function onLoaded(evt) {
var tableData = [
["PID01", "Fluffy Bear", 599, 600, 20, "Toy", "bear.png"],
["PID02", "Rubber Ducky", 1599, 40, 5, "Toy", "duck.png"],
["PID03", "Cool Handbag", 599, 1, 2, "Fashion", "bag.png"],
["PID04", "Fidget Spinner", 999, 120, 10, "Toy", "spinner.png"],
["PID05", "Lame Handbag", 4599, 60, 3, "Fashion", "bag.png"],
["PID06", "UltraMega Genuine Laptop", 170599, 20, 2, "Technology", "laptop.png"],
];
populateTable(tableData);
var categoryNames = ["All", "Fashion", "Toy", "Technology"];
populateSelect(byId('catSelector'), categoryNames);
qs('select').addEventListener('change', updateFilter, false);
}
function populateSelect(selElem, data) {
selElem.innerHTML = '';
data.forEach(txt => selElem.appendChild(new Option(txt, txt)));
}
function populateTable(data) {
data.forEach(appendRow);
function appendRow(itemData, itemIndex, items) {
let newRow = byId('productRowTemplate').content.cloneNode(true);
let cells = Array.from(newRow.firstChild.cells);
cells.forEach((cell, index) => {
if (index == 2)
cell.textContent = '$' + (itemData[index] / 100).toFixed(2);
else
cell.textContent = itemData[index];
});
// cells[0].textContent = itemData[0];
// cells[1].textContent = itemData[1];
// cells[2].textContent = '$'+(itemData[2]/100).toFixed(2);
// cells[3].textContent = itemData[3];
// cells[4].textContent = itemData[4];
// cells[5].textContent = itemData[5];
byId('storeItemOutput').tBodies[0].appendChild(newRow);
}
}
function updateFilter() {
let filter = byId('catSelector').value;
let prodRows = qsa('#storeItemOutput > tbody > tr');
if (filter == 'All') {
prodRows.forEach(row => row.classList.remove('notShown'));
} else {
prodRows.forEach(
row => {
if (row.cells[5].textContent == filter)
row.classList.remove('notShown');
else
row.classList.add('notShown');
}
);
}
}
.notShown {
display: none;
}
.price,
.qty,
.max {
text-align: right;
}
<template id='productRowTemplate'><tr>
<td class='id'></td>
<td class='name'></td>
<td class='price'></td>
<td class='qty'></td>
<td class='max'></td>
<td class='cat'></td>
<td><img class='icon'/></td>
</tr></template>
<body>
Filter:
<select id='catSelector'></select>
<table id='storeItemOutput'>
<thead>
<tr>
<th>ID</th>
<th>Product</th>
<th>Price</th>
<th>Qty</th>
<th>Max</th>
<th>Category</th>
<th>Image</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
Related
I want to be able to print out the next three upcoming train departure time, arrival time and train number when using Axios in JavaScript in a table that I have created with HTML.
I do get the output result after I have typed in the city name in the search bar and clicked search. However, the problem is that I get the output for the next upcoming train numbers in the same table cell, and same issue happens with the departure and arrival time as you can see down below in the image link.
Output result
I have tried changing the CSS using display: flex; but it doesn't work. I have even tried hard coding the array index using 0, 1, 2 instead of i and removed the for-loop but then the output result will only show one of the latest train departure time, arrival time and train number, and not all three of them at the same time which is what I wish to have, which is like this:
Trainnr: Departure Arrival
Regional Tåg 971 19:11:00 19:48:00
Regional Tåg 863 19:21:00 19:53:00
Länstrafik - Tåg 40 19:26:00 20:25:00
This is my code in the HTML for the train table:
<section class="trainSchedule">
<strong><p class="train-title">Railway Time Table</p></strong>
<div class="box">
Does the train go to Stockholm?
<br />
I'm departing from..
<input type="text" class="request-input" placeholder="Ex: Göteborg" />
<button class="request-btn">Search...</button>
<div class="message-box">
<table class="table">
<thead>
<tr>
<th class="trainNumber">TrainNr:</th>
<th class="departure">Departure:</th>
<th class="arrival">Arrival:</th>
</tr>
<tr>
<td class="trainNum"></td>
<td class="trainDep"></td>
<td class="trainArr"></td>
</tr>
</thead>
</table>
</div>
Departing from: <strong><div class="response-result"></div></strong>
</div>
</section>
And here is vanilla JavaScript code using axios:
let reqBtn = document.querySelector(".request-btn");
let reqInput = document.querySelector(".request-input");
let respResult = document.querySelector(".response-result");
const API_KEY = "xxxxxxxxxxxxxxx";
const DEST_ID_FIXED = "740000001";
function getOriginIdURL(city, key) {
return `https://api.resrobot.se/v2.1/location.name?input=${city}&format=json&accessId=${key}`;
}
function getRouteURL(originId, destId, key) {
return `https://api.resrobot.se/v2.1/trip?format=json&originId=${originId}&destId=${destId}&passlist=true&showPassingPoints=true&accessId=${key}`;
}
function findRoute(fromCity) {
let searchURL = getOriginIdURL(fromCity, API_KEY);
axios.get(searchURL).then((response) => {
let data = response.data;
let originId = data.stopLocationOrCoordLocation[0].StopLocation.extId;
let routeURL = getRouteURL(originId, DEST_ID_FIXED, API_KEY);
axios.get(routeURL).then((response) => {
let data = response.data;
// console.log(response.data.Trip[0].LegList.Leg[0].Product[0].name);
let trainNum = document.querySelector(".trainNum");
let trainDep = document.querySelector(".trainDep");
let trainArr = document.querySelector(".trainArr");
for (let i = 0; i < 3; i++) {
trainNum.textContent += "\n" + data.Trip[i].LegList.Leg[0].Product[0].name;
trainDep.textContent += "\n" + data.Trip[i].Origin.time;
trainArr.textContent += "\n" + data.Trip[i].Destination.time;
let table = document.querySelector('table');
let tr = document.createElement('tr');
let tr2 = document.createElement('td');
let tr3 = document.createElement('td');
let tr4 = document.createElement('td');
tr2 = trainNum.textContent;
tr3 = trainDep.textContent;
tr4 = trainArr.textContent;
// tr.append(tr2, tr3, tr4);
table.append(tr);
}
respResult.textContent = `${reqInput.value}`;
// console.log(data.Trip[0].Origin.time);
// console.log(data.Trip[1].Origin.time);
// console.log(data.Trip[2].Destination.name);
// console.log("");
});
});
}
reqBtn.addEventListener("click", (event) => {
findRoute(reqInput.value);
});
What am I doing wrong here?
I really appreciate if anyone can help me out and explain.
Thank you
I'm just re-writing the part where you process the response, because I think that's the only part of interest here. Basically, you should create your new row (<tr>) and your new cells (<td>) before to add content to them. And then you set the text content of them. And then you append the row to the table.
axios.get(routeURL).then((response) => {
let data = response.data;
for (let i = 0; i < 3; i++) {
let newRow = document.createElement("tr");
let trainNumCell = document.createElement("td");
trainNumCell.classList.add("trainNum");
newRow.append(trainNumCell);
let trainDepCell = document.createElement("td")
trainDepCell.classList.add("trainDep")
newRow.append(trainDepCell);
let trainArrCell = document.createElement("td")
trainArrCell.classList.add("trainArr")
newRow.append(trainArrCell);
trainNumCell.textContent = data.Trip[i].LegList.Leg[0].Product[0].name;
trainDepCell.textContent = data.Trip[i].Origin.time;
trainArrCell.textContent = data.Trip[i].Destination.time;
let table = document.querySelector('table');
table.append(newRow);
}
respResult.textContent = `${reqInput.value}`;
});
Concerning the HTML, you could simplify it, you don't to pre-create a row. So you table could be only this
<table class="table">
<thead>
<tr>
<th class="trainNumber">TrainNr:</th>
<th class="departure">Departure:</th>
<th class="arrival">Arrival:</th>
</tr>
</thead>
</table>
I've been stuck trying to filter a table, based on one of three values assigned to the last column of a table. The table is created via user input, the last column is a select option containing either 'Node.JS', 'ReactJS' or AngularJS'.
If the user wants the table to be sorted by 'Node.JS' for example, I want all data/rows with the value of 'Node.JS' to be displayed, and the rest to be removed. I also have all the data saved to localStorage, so something like
const filtered = tableData.filter(everything containing Node.JS));
everythingElse.innerHtml.remove
would work, then rebuild the table using the data now stored in filtered. I just can't seem to get it to work. Any help would be greatly greatly appreciated.
Here's the code:
function filterTable() {
const filterBy = document.getElementById('filter'); // filter option select
const savedData = JSON.parse(localStorage.getItem('data'));
const rows = table.rows;
if(filterBy.value === 'Node.JS'){
const filtered = savedData.filter(rows[4].value === 'Node.JS');
console.log(filtered);
}
} // TBH idk if I'm even going in the right direction. Pls help haha
Just in case it helps, here's the function creating the table.
function createTable(rowData) {
const deletebtn = document.createElement('button');
deletebtn.innerText = 'Delete Entry';
const newRow = table.insertRow(table.rows.length); // table.rows.length is the index where newRow gets inserted
newRow.appendChild(deletebtn);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
const cell3 = newRow.insertCell(2);
const cell4 = newRow.insertCell(3);
const cell5 = newRow.insertCell(4);
cell1.innerHTML = rowData ? rowData.name : name.value;
cell2.innerHTML = rowData ? rowData.nachname : nachname.value;
cell3.innerHTML = rowData ? rowData.bday : bday.value;
cell4.innerHTML = rowData ? rowData.beruf : beruf.value;
cell5.innerHTML = rowData ? rowData.veranstaltung : veranstaltung.value;
deletebtn.addEventListener('click', deleteRow)
}
I modified your approach of creating table, I like this more because of readability and simplicity but you can apply same to your pattern if you want to...
let createTable2 = (element, rowData) => {
let mainTable = document.getElementById("main-table");
let array = rowData;
if(element.value !== "nofilter"){
array = rowData.filter(item => item.veranstaltung.toLowerCase() === element.value)
}
let tableContent = "";
for (let i = 0; i < array.length; i++) {
tableContent += `
<tr>
<td>
${array[i].name}
</td>
<td>
${array[i].nachname}
</td>
<td>
${array[i].bday}
</td>
<td>
${array[i].beruf}
</td>
<td>
${array[i].veranstaltung}
</td>
<td>
<button>Delete</button>
</td>
</tr>
`
}
mainTable.innerHTML = tableContent;
}
let rowData = [
{
"name": "Tiffany",
"nachname": "Campbell",
"bday": "11/11/11",
"beruf": "dono",
"veranstaltung": "ReactJS"
},
{
"name": "Jack",
"nachname": "Traktor",
"bday": "11/11/11",
"beruf": "dono",
"veranstaltung": "NodeJS"
},
{
"name": "Someone",
"nachname": "Else",
"bday": "11/11/11",
"beruf": "dono",
"veranstaltung": "AngularJS"
}
]
createTable2(document.getElementById("filter"), rowData);
<select id="filter" onchange="createTable2(this, rowData)">
<option value="nofilter">No Filter</option>
<option value="angularjs">AngularJS</option>
<option value="reactjs">ReactJS</option>
<option value="nodejs">NodeJS</option>
</select>
<table border="1" id="main-table">
</table>
I have been trying to solve this for days.I would greatly appreciate any help you can give me in solving this problem. I have a table like the following:
ID Name Study
1111 Angela XRAY
2222 Bena Ultrasound
3333 Luis CT Scan
1111 Angela Ultrasound
3333 Luis XRAY
3333 Luis LASER
and I want to group them like:
ID Name Study
GROUP BY id(1111) 2 hits "+"
2222 Bena Ultrasound
GROUP BY id(3333) 3 hits "+"
AND if "+" is clicked then it will expand:
ID Name Study
GROUP BY id(1111) 2 hits "-"
1111 Angela XRAY
1111 Angela Ultrasound
2222 Bena Ultrasound
GROUP BY id(3333) 3 hits "-"
3333 Luis CT Scan
3333 Luis Ultrasound
3333 Luis LASER
There is a demo that I found on stackoverflow(http://jsfiddle.net/FNvsQ/1/) but the only problem I have is I want to include all rows having the same id under a dynamic header like
grouped by id(1111) then the expand/collapse icon (+/-)
var table = $('table')[0];
var rowGroups = {};
//loop through the rows excluding the first row (the header row)
while(table.rows.length > 0){
var row = table.rows[0];
var id = $(row.cells[0]).text();
if(!rowGroups[id]) rowGroups[id] = [];
if(rowGroups[id].length > 0){
row.className = 'subrow';
$(row).slideUp();
}
rowGroups[id].push(row);
table.deleteRow(0);
}
//loop through the row groups to build the new table content
for(var id in rowGroups){
var group = rowGroups[id];
for(var j = 0; j < group.length; j++){
var row = group[j];
if(group.length > 1 && j == 0) {
//add + button
var lastCell = row.cells[row.cells.length - 1];
$("<span class='collapsed'>").appendTo(lastCell).click(plusClick);
}
table.tBodies[0].appendChild(row);
}
}
//function handling button click
function plusClick(e){
var collapsed = $(this).hasClass('collapsed');
var fontSize = collapsed ? 14 : 0;
$(this).closest('tr').nextUntil(':not(.subrow)').slideToggle(400)
.css('font-size', fontSize);
$(this).toggleClass('collapsed');
}
Here is the answer to my own question.
First id's are added to the table and the rows and there's a small change to the JS:
var table = $('table')[0];
var rowGroups = {};
//loop through the rows excluding the first row (the header row)
while (table.rows.length > 1) {
var row = table.rows[1];
var id = $(row.cells[0]).text();
if (!rowGroups[id]) rowGroups[id] = [];
if (rowGroups[id].length > 0) {
row.className = 'subrow';
$(row).slideUp();
}
rowGroups[id].push(row);
table.deleteRow(1);
}
//loop through the row groups to build the new table content
for (var id in rowGroups) {
var group = rowGroups[id];
for (var j = 0; j < group.length; j++) {
var row = group[j];
var notSubrow = false;
if (group.length > 1 && j == 0) {
//add + button
var lastCell = row.cells[row.cells.length - 1];
var rowId = row.id;
var tableId = table.id;
notSubrow = true;
//$("<span class='collapsed'>").appendTo(lastCell).click(plusClick);
}
table.tBodies[0].appendChild(row);
if (notSubrow) {
$('#' + tableId).find('#' + rowId).attr('class', 'subrow');
$('#' + tableId).find('#' + rowId).before("<tr class='subrowHeader' style='background:#E6E6FA;border-bottom:1px solid #708AA0 !important'><td colspan='3'> group by " + $(row.cells[0]).text() + " (" + group.length + ")" + "<span class='collapsed' onclick='plusClick(this)' style='float:left;display:inline'></td></tr>");
$('#' + tableId).find('#' + rowId).hide();
}
}
}
//function handling button click
function plusClick(e) {
var collapsed = $(e).hasClass('collapsed');
var fontSize = collapsed ? 14 : 0;
$(e).closest('tr').nextUntil(':not(.subrow)').slideToggle('fast').css('font-size', fontSize);
$(e).toggleClass('collapsed');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table1">
<tr id="tr1">
<th>Parent ID</th>
<th>Parent Name</th>
<th>Study</th>
</tr>
<tr id="tr2">
<td>1111</td>
<td>Angela</td>
<td>XRAY</td>
</tr>
<tr id="tr3">
<td>2222</td>
<td>Bena</td>
<td>Untrasound</td>
</tr>
<tr id="tr4">
<td>3333</td>
<td>Luis</td>
<td>CT Scan</td>
</tr>
<tr id="tr5">
<td>1111</td>
<td>Angela</td>
<td>Untrasound</td>
</tr>
<tr id="tr6">
<td>3333</td>
<td>Luis</td>
<td>LCD</td>
</tr>
<tr id="tr7">
<td>3333</td>
<td>Luis</td>
<td>LASER</td>
</tr>
</table>
*Inorder to test copy and paste the code into http://jsfiddle.net/FNvsQ/1/ &
In the Frameworks & Extensions panel, set onLoad to No wrap - in body.
As a comparison, here's a POJS function that is functionally equivalent in the same amount of code. Doesn't use a large external library though.
It uses the same algorithm of collecting all rows with the same value in the first cell, then modifies the table to insert header rows and group the data rows.
// Group table rows by first cell value. Assume first row is header row
function groupByFirst(table) {
// Add expand/collapse button
function addButton(cell) {
var button = cell.appendChild(document.createElement('button'));
button.className = 'toggleButton';
button.textContent = '+';
button.addEventListener('click', toggleHidden, false);
return button;
}
// Expand/collapse all rows below this one until next header reached
function toggleHidden(evt) {
var row = this.parentNode.parentNode.nextSibling;
while (row && !row.classList.contains('groupHeader')) {
row.classList.toggle('hiddenRow');
row = row.nextSibling;
}
}
// Use tBody to avoid Safari bug (appends rows to table outside tbody)
var tbody = table.tBodies[0];
// Get rows as an array, exclude first row
var rows = Array.from(tbody.rows).slice(1);
// Group rows in object using first cell value
var groups = rows.reduce(function(groups, row) {
var val = row.cells[0].textContent;
if (!groups[val]) groups[val] = [];
groups[val].push(row);
return groups;
}, Object.create(null));
// Put rows in table with extra header row for each group
Object.keys(groups).forEach(function(value, i) {
// Add header row
var row = tbody.insertRow();
row.className = 'groupHeader';
var cell = row.appendChild(document.createElement('td'));
cell.colSpan = groups[value][0].cells.length;
cell.appendChild(
document.createTextNode(
'Grouped by ' + table.rows[0].cells[0].textContent +
' (' + value + ') ' + groups[value].length + ' hits'
)
);
var button = addButton(cell);
// Put the group's rows in tbody after header
groups[value].forEach(function(row){tbody.appendChild(row)});
// Call listener to collapse group
button.click();
});
}
window.onload = function(){
groupByFirst(document.getElementById('table1'));
}
table {
border-collapse: collapse;
border-left: 1px solid #bbbbbb;
border-top: 1px solid #bbbbbb;
}
th, td {
border-right: 1px solid #bbbbbb;
border-bottom: 1px solid #bbbbbb;
}
.toggleButton {
float: right;
}
.hiddenRow {
display: none;
}
<table id="table1">
<tr id="tr1">
<th>Parent ID</th>
<th>Parent Name</th>
<th>Study</th>
</tr>
<tr id="tr2">
<td>1111</td>
<td>Angela</td>
<td>XRAY</td>
</tr>
<tr id="tr3">
<td>2222</td>
<td>Bena</td>
<td>Ultrasound</td>
</tr>
<tr id="tr4">
<td>3333</td>
<td>Luis</td>
<td>CT Scan</td>
</tr>
<tr id="tr5">
<td>1111</td>
<td>Angela</td>
<td>Ultrasound</td>
</tr>
<tr id="tr6">
<td>3333</td>
<td>Luis</td>
<td>LCD</td>
</tr>
<tr id="tr7">
<td>3333</td>
<td>Luis</td>
<td>LASER</td>
</tr>
</table>
Let's say I have a Javascript Array of Product Objects
function Product() {
this.Name = "";
this.Cost = "";
this.Color = "";
}
var ProductsArray = [];
var product1 = new Product();
product1.Name = "Name1";
product1.Cost = "Cost1";
product1.Color = "Color1";
var product2 = new Product();
product2.Name = "Name2";
product2.Cost = "Cost2";
product2.Color = "Color2";
var product3 = new Product();
product3.Name = "Name3";
product3.Cost = "Cost3";
product3.Color = "Color3";
ProductsArray.push(product1);
ProductsArray.push(product2);
ProductsArray.push(product3);
ProductsArray now has the following
product1: [Name1, Cost1, Color1],
product2: [Name2, Cost2, Color2],
product3: [Name3, Cost3, Color3]
How do I loop through this Array of Objects so that I'm able to create table dynamically through jQuery which as the following format:
It's sort of like a table whose columns are horizontal
+-----------------------------------+
| Names | Name 1 | Name 2 | Name 3 |
+-----------------------------------+
| Costs | Cost 1 | Cost 2 | Cost 3 |
+-----------------------------------+
| Colors | Color1 | Color2 | Color3 |
+-----------------------------------+
<table>
<tr>
<th>Names</th>
<td>Name1</>
<td>Name2</>
<td>Name3</>
</tr>
<tr>
<th>Costs</th>
<td>Cost1</>
<td>Cost2</>
<td>Cost3</>
</tr>
<tr>
<th>Colors</th>
<td>Color1</>
<td>Color2</>
<td>Color3</>
</tr>
<table>
I guess the problem I'm having is since I loop through the Array in this fashion:
for (var i = 0; i < ProductsArray.length; i++) {
ProductsArray[i].Name
ProductsArray[i].Cost
ProductsArray[i].Color
}
I can only go through one object at time so I need a way to go through the values of each section each iteration, for example I need to go through the values of each Name and put them in <td> columns, then go through the values of each Cost and put them in a <td> etc...
I would suggest a slightly different approach. First I'd pass the arguments in the constructor, then I'd create the products array with instances and a function to make the HTML for your table.
You can use this with any collection, not only instances, but regular objects as well, just pass an array of objects, the properties to show, and the headers for each of those properties.
Demo: http://jsbin.com/gibez/1
function Product(name, cost, color) {
this.name = name;
this.cost = cost;
this.color = color;
}
var products = [
new Product('name1', 'cost1', 'color1'),
new Product('name2', 'cost2', 'color2'),
new Product('name3', 'cost3', 'color3')
];
function pluck(prop) {
return function(x) {
return x[prop];
};
}
function table(data, props, headers) {
var cells = props.map(function(prop) {
return '<td>'+ data.map(pluck(prop)).join('</td><td>') +'</td>';
});
var rows = headers.map(function(head, i) {
return '<tr><th>'+ head +'</th>'+ cells[i] +'<tr>';
});
return '<table>'+ rows.join('') +'</table>';
}
var tableHtml = table(
products,
['name', 'cost', 'color'],
['Names', 'Costs', 'Colors']
);
You can select the 3 trs ahead of time and use those as you iterate the array:
http://jsfiddle.net/QR7UZ/
<table>
<tr>
<th>Names</th>
</tr>
<tr>
<th>Costs</th>
</tr>
<tr>
<th>Colors</th>
</tr>
</table>
var $trs = $('table tr');
var $nameTr = $trs.eq(0);
var $costTr = $trs.eq(1);
var $colorTr = $trs.eq(2);
$.each(ProductsArray, function(idx, item) {
$('<td />').text(item.Name).appendTo($nameTr);
$('<td />').text(item.Cost).appendTo($costTr);
$('<td />').text(item.Color).appendTo($colorTr);
});
Hmm...you could add to three separate strings, that would each end up constituting a table row. Set up a skeleton table beforehand with the <tr> elements already in there, then run the script to fill each of them with <td> elements.
Maybe something like this (not sure how you're creating the elements, so I'll just use the jQuery .append() function).
HTML:
<table>
<tr class="name">
<th>Name</th>
</tr>
<tr class="cost">
<th>Cost</th>
</tr>
<tr class="color">
<th>Color</th>
</tr>
</table>
JavaScript:
var nameHtml = "";
var costHtml = "";
var colorHtml = "";
// Building strings
for (var i = 0; i < ProductsArray.length; i++) {
nameHtml += "<td>" + ProductsArray[i].Name + "</td>";
costHtml += "<td>" + ProductsArray[i].Cost + "</td>";
colorHtml += "<td>" + ProductsArray[i].Color + "</td>";
}
// Adding to rows
$(".name").append(nameHtml);
$(".cost").append(costHtml);
$(".color").append(colorHtml);
Here's a JSFiddle that demonstrates the example. There are plenty of ways to do this though, others have suggested some interesting ones. Main benefit here is that you can switch around table rows freely in the HTML without needing to change the JavaScript. Let me know if you have any questions. Hope this helps!
how do I check for duplicate row in a table using javascript? The following is part of my code:
<table id="t1">
<tr>
<td>Text A</td>
<td>Text B</td>
<td>Cbx A</td>
</tr>
<% int count1 = -1;
for(int i=0; i<3; i++) { %>
<tr>
<td><input type="text" id="textA<%=i%>"></td>
<td><input type="text" id="textB<%=i%>"></td>
<td><select name="cbx_A<%=i%>">
<option value="A">Option1</option>
<option value="B">Option2</option>
</select>
</td
</tr>
<%count1 =i;
}%>
<tr>
<td><input type="button" onclick="check(<%=count1%>)" value="Check"></td>
</tr>
</table>
So based on this code, I will have 3 rows of text A,textB and cbxA. With that, how do I check whether user input the same values for 2 of the rows or all three rows?
I tried using servlet but theres too much work involve. So yeah is there a way to do this using java script instead?
Thanks in advance for any possible help.
Using this code it will check for duplication in one table column
then take all rows of table that are duplicated and put their ids in array
so you will get an array of rows id
but ur table has to have an id for each row
var columnNumber = 1;
var table = document.getElementById('t1');
var rowLength = table.rows.length;
var arrReocrds = new Array();
var arrCount = 0;
var listCount = 0;
var arr = new Array();
$('#t1 td:nth-child(' + colNumber + ')').each(function () {
var recordValue = $(this).html().trim();
var flagFirstTime = true;
//loop through table to check redundant of current record value
for (var i = 1; i < rowLength; i += 1) {
{
var row = table.rows[i];
var recordId = //put here row.id or anything that you can put it in the list
var cell = row.cells[colNumber - 1];
var value = cell.innerText.trim();
if (value == recordValue) {
if (!arr.contains(value)) {
if (flagFirstTime != true) {
arrReocrds[arrCount] = recordId;
arrCount++;
}
else
flagFirstTime = false;
}
else
break;
}
}
}
//create list for items in column
//to be sure that the item that has been taken and checked never be checked again by their other redundant records
arr[listCount] = recordValue;
listCount++;
});