I have got a simple loop that puts data from a list to the table:
standings.forEach(function(item, i) {
const rowData = document.createElement("tr");
const tdData = document.createElement("td");
const tdData2 = document.createElement("td");
const tdData3 = document.createElement("td");
const tdData4 = document.createElement("td");
const tdData5 = document.createElement("td");
tbody.appendChild(rowData);
tdData.textContent = item.position;
rowData.appendChild(tdData);
tdData2.textContent = `${item.name} ${item.surname}`;
rowData.appendChild(tdData2);
tdData3.textContent = item.data2;
rowData.appendChild(tdData3);
tdData4.textContent = item.point;
rowData.appendChild(tdData4);
tdData5.textContent = item.fruits;
rowData.appendChild(tdData5);
})
Anyone knows how I can automate this process? I don't think, that my way is super efficient, so I am looking for another answer.
I typically break repeating elements down into smaller pieces, and then repeat as needed to make it easier to read. For instance, you are creating a lot of 'td' elements with text inside it, so I would start with something like:
function newElementWithText( innerText )
{
const td = document.createElement("td");
td.textContent = innerText;
return td;
}
to handle that part. If you incorporate that solely into your code, you would have:
standings.forEach(function(item, i) {
const rowData = document.createElement("tr");
rowData.appendChild(
newElementWithText(item.position) );
rowData.appendChild(
newElementWithText(`${item.name} ${item.surname}`);
rowData.appendChild( newElementWithText(item.data2);
rowData.appendChild( newElementWithText(item.point);
rowData.appendChild(
newElementWithText(item.fruits) );
tbody.appendChild(rowData);
}
This can be made more readable using an array of the data that is needed, and then mapping it into the new td element, and then finally appending it.
standings.forEach(function(item, i) {
const rowData = document.createElement("tr");
const data = [
item.position,
`${item.name} ${item.surname}`,
item.data2,
item.point,
item.fruits
];
//Creates an array of the 'td' elements with text.
var tdElements = data.map( x => newElementWithText(x) );
//Iterates over the new array and appends to the rowData.
tdElements.map( x => rowData.appendChild(x) );
tbody.appendChild(rowData);
}
Full disclaimer, I have not fully tested this code for syntax errors, but it works in theory.
Related
I am trying to generate a table from an array with a searching feature. With every letter typed in the search bar the items that contain that specific string will be displayed.
I have come to the conclusion to generate the whole table with every keystroke rather than editing the current.
This is where I am at:
What´s currently typed in the searchbar:
let searchBar = document.getElementById('search-input');
let value = " ";
searchBar.addEventListener(`keyup`, function(){
value = this.value
How I make the table:
let tableUsers = document.getElementById("tabell");
function drawTable() {
let table = document.createElement("table");
let tableHead = document.createElement("thead");
let colHeads = ["Name"];
for (let header of colHeads) {
let cell = document.createElement("th")
cell.innerHTML = header;
tableHead.appendChild(cell);
}
table.appendChild(tableHead)
for (let x of people) {
let row = document.createElement("tr");
let name = document.createElement("td");
name.innerHTML = x.name.first + " " + x.name.last;
row.appendChild(name);
table.appendChild(row);
}
tableUsers.appendChild(table);
}
drawTable()
I am trying this:
let str = x.name.first.toLowerCase()
if (str.includes(value)){
//code
}
Is it possible to do it this way? Or possible at all using JS and large arrays without using a lot of pc resources?
Any help is greatly appreciated!
Inside if statement, you need to create new array then push the values inside it then you can pass a new people as a parameter to drawTable function and call it like drawTable(people)
Is there any way to create variable from String inside the array with the name of the String?
something like this:
const array = ["type","name","hours","photos","place","price"];
array.forEach(item =>{
let item = document.crea.....
//but it should work like let array[index] = docu.......
})
The reason for this is that I wanted to make this code look a bit nicer and its obvious, that there are quite a lot things repeating.
const type = document.createElement("td");
const name = document.createElement("td");
const hours = document.createElement("td");
const photos = document.createElement("td");
const place = document.createElement("td");
const price = document.createElement("td");
type.innerHTML = element.type;
name.innerHTML = element.name;
hours.innerHTML = element.hours;
photos.innerHTML = element.photos;
place.innerHTML = element.place;
price.innerHTML = element.price;
tr.appendChild(type);
tr.appendChild(name);
tr.appendChild(hours);
tr.appendChild(photos);
tr.appendChild(place);
tr.appendChild(price);
Try use var or let instead const,works for me always.
And remember foreach is a kind of loop means
var mytd = document.createElement("td");mytd.innerHTML = element.{item};tr.appendChild(mytd);
I know this doesn't directly answer your question about variable names, but this should be the code you need to get your result.
array.forEach(item => {
const elem = tr.appendChild(document.createElement("td"));
elem.innerHTML = item;
})
You don't really need to use your array to generate the variable name as the forEach handles each item in the array separately.
I am practising DOM manipulation using native JS my issue right now is I used a table and I am having a problem in appending my multiple columns to the table row "". Here's what I did but it will only add the first column I created.
let form = document.querySelector('#form-task');
let taskTable = document.querySelector('#tasklist-table tbody');
let addTask = (e) => {
e.preventDefault();
let task_description = document.querySelector('#input-task-description').value;
let task_notes = document.querySelector('#input-task-notes').value;
let row = document.createElement('tr');
// task description
let col1 = document.createElement('td');
col1.appendChild(document.createTextNode(task_description));
// task note
let col2 = document.createElement('td');
col2.appendChild(document.createTextNode(task_notes));
// delete button
let col3 = document.createElement('td');
// create button delete
let btn_del = document.createElement('button');
btn_del.className = 'button alert tiny center-btn"';
btn_del.appendChild(document.createTextNode('x'));
// append button to columnd 3
col3.appendChild(btn_del);
row.appendChild(col1, col2, col3); // IT IS NOT WORKING, HOW CAN I MERGE MY CREATED COLUMN THEN PASS TO THE ROW?
// append row to table
taskTable.appendChild(row);
}
appendChild only accepts a single child as an argument to be appended.
While you could call row.appendChild multiple times with the 3 <td>s, it might be easier to create the td and append it to the tr at the same time, and to use textContent instead of createTextNode:
const taskDescription = document.querySelector('#input-task-description').value;
const taskNotes = document.querySelector('#input-task-notes').value;
const row = taskTable.appendChild(document.createElement('tr'));
row.appendChild(document.createElement('td')).textContent = taskDescription;
row.appendChild(document.createElement('td')).textContent = taskNotes;
const delTd = row.appendChild(document.createElement('td'));
const delBtn = delTd.appendChild(document.createElement('button'));
delBtn.className = 'button alert tiny center-btn"';
delBtn.textContent = 'x';
Please do append child separately.
row.appendChild(col1);
row.appendChild(col2);
row.appendChild(col3);
To get something close to your original attempt, you can just put the elements to be appended in an array, and iterate that array.
[col1, col2, col3].forEach(col => row.appendChild(col));
That's not too far off from where you wanted to be.
However, I'm inclined toward making a function that receives an object structure representing the DOM structure you're creating.
let addTask = (e) => {
// e.preventDefault();
const taskTable = document.querySelector("#task-table");
const task_description = document.querySelector('#input-task-description').value;
const task_notes = document.querySelector('#input-task-notes').value;
create({
name: "tr",
children: [
{name: "td", textContent: task_description},
{name: "td", textContent: task_notes},
{name: "td", children: [
{name: "button", className: "button alert tiny center-btn", textContent: "x"},
]},
],
}, taskTable);
}
addTask();
addTask();
addTask();
console.log(document.querySelector("#task-table").outerHTML);
function create(obj, parent=document.createDocumentFragment()) {
if (!obj) return parent;
if (typeof obj === "string") {
parent.appendChild(document.createTextNode(obj));
return parent;
}
if (Array.isArray(obj)) {
obj.forEach(o => create(o, parent));
return parent;
}
const {name, children, ...props} = obj;
if (!name || typeof name !== "string") {
return parent; // or throw exception
}
const el = parent.appendChild(document.createElement(name));
for (const [key, val] of Object.entries(props || {})) {
el[key] = val;
}
return create(children, el);
}
<input id=input-task-description value=foo>
<input id=input-task-notes value=bar>
<table id=task-table>
</table>
This is just an example implementation, but you can create your DOM structures in a very concise and clear way like this.
In my code, I am doing stuff to a table based upon a column or row click.
I only saw the way of getting the table using parentElement
So I might have
<div id="table-container">
</div>
let table = document.createElement('table');
table.id = 'my-table';
let thead = table.createTHead();
let thead_row = thead.insertRow();
let thead_cell = thead_row.insertCell();
thead_cell.textContent = "Products";
let tbody = table.createTBody();
let tbody_row1 = thead.insertRow();
let tbody_cell1 = tbody_row1.insertCell();
tbody_cell1.textContent = "apple";
let tbody_row2 = thead.insertRow();
let tbody_cell2 = tbody_row1.insertCell();
tbody_cell1.textContent = "orange";
document.getElementById('table-container').appendChild(table);
So here I have an easy reference to the table which I might not have in my code elsewhere and I do not want to pass the table all over.
So let's say I put an eventlistener on a row like so:
tbody_row2.addEventListener('click', function() {
alert(tbody_row2.parentElement.parentElement.id);
})
to get the table id from the row itself (if I did not have the easy table reference), I need to use
[element].parentElement.parentElement.id
which to me is not always clear it is a table.
To get the rows out of a table, I can write.
table.rows;
Is there anything similar to:
row.table;
for an upward reference?
You could use the .closest element method: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
If you have an row element, you can run this command against that row element and it will return the first parent element with the selector you pass in
const row = table.rows[0];
const parentTable = row.closest('table');
I have script in js that generate html table with 1k elements.
Script took 2~s for generate.
How I can improve performance of it?
Here my script:
var
i = 0,
larr = [],
lvls = [/* 1k int's */];
while (1000!==i) {
larr[i]=lvls[i]+' '+(++i);
}
lvls = [];
var lvl = document.getElementById('lvl');
lvl.innerHTML = `<table id="levels">
<tr>
<th>LvL</th><th>Experience</th>
</tr>`+
larr.join(',')
.replace(/(\d+)\s(\d+),?/g, `<tr><td>$2</td><td>$1</td></tr>`)
.replace(/,/g, ``)
+`</table>`;
larr = [];
Here full script:
http://codepen.io/anon/pen/NNZabz
Ps. I want to use the only js; I don't want store result on server.
Normally innerHTML is very performance lacking. I would suggest generating the elements, and appending them to a table element. I also got rid of larr completely since it looks unnecessary.
You can also put that part of the code into the while loop.
var i = 0,
lvls = [];
var lvl = document.getElementById('lvl');
//Make a table
var table = document.createElement('table');
table.id = 'levels';
//Add that header HTML
table.innerHTML = '<tr><th>LvL</th><th>Experience</th></tr>'
//Add that to the lvl element so it renders
lvl.appendChild(table);
var d = document.createDocumentFragment();
//Execute your level creating loop while appending children to the fragment
while (1000!==i) {
var _tr = document.createElement('tr');
var _t1 = document.createElement('td');
var _t2 = document.createElement('td');
_tr.appendChild(_t1);
_tr.appendChild(_t2);
_t1.innerHTML = lvls[i];
_t1.innerHTML = ++i;
d.appendChild(_tr);
}
//Add the document fragment to the table
table.appendChild(d);
Based on a quick test, this will execute in ~200ms