Optimize generating html table in js - javascript

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

Related

Generate new table when searching

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 + "&nbsp" + 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)

Creating a loop for inserting data inside the table

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.

JavaScript Cloned Table Rows - reset value

I have a form/table set up that's cloning rows with specific valued names so that they can be processed separately once the form submits. All seems to be well unless you fill out information on the 5th row (the row being cloned) and then it copies all of the data over into the cloned row.
Is there an easy way to reset the values to NULL and 0 during the cloning process?
(I have two rows on bottom that are tallying/totalling each column, hence the tr:nth-last-child(2))
var totalRows = 5;
function addrow() {
totalRows++;
var clonedRow = $("table#maintable tr:nth-child(5)").clone(); //this will grab the 5th table row.
//get the textfield
var tfName = $("input.name",clonedRow);
var tfproA = $("input.proA",clonedRow);
var tfproB = $("input.proB",clonedRow);
var tfproC = $("input.proC",clonedRow);
var tfproD = $("input.proD",clonedRow);
var tfproE = $("input.proE",clonedRow);
var tfproF = $("input.proF",clonedRow);
var tfproG = $("input.proG",clonedRow);
var tfproH = $("input.proH",clonedRow);
var tfproI = $("input.proI",clonedRow);
var tfproJ = $("input.proJ",clonedRow);
var tfproK = $("input.proK",clonedRow);
var tfproL = $("input.proL",clonedRow);
var tfproM = $("input.proM",clonedRow);
var tfproN = $("input.proN",clonedRow);
//change their names
tfName.attr("name","name"+totalRows);
tfproA.attr("name","proA"+totalRows);
tfproB.attr("name","proB"+totalRows);
tfproC.attr("name","proC"+totalRows);
tfproD.attr("name","proD"+totalRows);
tfproE.attr("name","proE"+totalRows);
tfproF.attr("name","proF"+totalRows);
tfproG.attr("name","proG"+totalRows);
tfproH.attr("name","proH"+totalRows);
tfproI.attr("name","proI"+totalRows);
tfproJ.attr("name","proJ"+totalRows);
tfproK.attr("name","proK"+totalRows);
tfproL.attr("name","proL"+totalRows);
tfproM.attr("name","proM"+totalRows);
tfproN.attr("name","proN"+totalRows);
$("table#maintable tr:nth-last-child(2)").before(clonedRow); //add the row back to the table before the last 2nd to last row
console.log('done')
}
You can chain together a call to val()
tfName.attr("name","name"+totalRows).val(0) or
tfName.attr("name","name"+totalRows).val('')

Create an array from JSON in Javascript

I've researched quite a bit on here and I can't seem to find something that will work for me. What I have is an application that I'm trying to have go out and return the next four bus arrival times for a bus stop. I am reaching out to an API that returns this data in a JSON file. The problem I am having is I can see my request go out via fiddler but I can't seem to get the data into an array. Below is the code that I'm dealing with right now. I'm trying to get the returned data into a table format which you can see I'm failing at.
Eventually I want to get a popup to appear when the user clicks on the Show me the next 4 bus arrival times but this was for testing purposes. I would love to have the users click on my button which calls this function and then something like a like table open with these values. If you can help with that within this code I would appreciate it as well.
JSON Data:
[{"ARRIVAL":"01:23P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"01:53P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"02:23P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"02:53P","ROUTE":"208","DIR":"E"}]
Code:
<script>
function getTimes(stopNumber) {
var busArrivalAPI = "http://blahblahblah/rtcTimes/" + stopNumber ";
$.getJSON(busArrivalAPI, function(busArrivals) {
var a = [];
for (var i = 0; i < busArrivals.length; i++) {
a[i] = [busArrivals[i].ROUTE, busArrivals[i].ARRIVAL, busArrivals[i].DIR];
document.getElementById("results").createElement("TR");
for (var b = 0; b < 3; b++) {
var x = document.createElement("TH");
var z = a[i][b];
var t = document.createTextNode(z);
x.appendChild(t);
document.getElementById('results').appendChild(x);
};
};
});
</script>
My DIV:
<div style="overflow-x:scroll; overflow-y:scroll;" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="title:'Bus Arrival Times', selected:true">
<table id = 'results'>
<tr>
<th>Route</th>
<th>Arrival Time</th>
<th>Direction</th>
</tr>
</table>
</div>
UPDATE: Ok, I've use the makeTable idea provide below and it works when I program as seen below hard coding the json data. However, when trying to use the $.getJSON I'm having some cross domain issues now and don't know how I can get my $.getJSON request working. Any input on how to get the data from my getJSON request work be great.
function getTimes(stopNumber) {
// This is the API address I need to hit. Trying to figure out how to incorporate that and remove the function getJSON where I have the data hard coded.
//var busArrivalAPI = "http://-----/rtcTimes/"+ stopNumber + "?jsoncallback=?";
function makeTable(busArrivals) {
// This will remove old values so table will only load current Times
var results = document.getElementById("results");
var rowCount = results.rows.length;
for (var x=rowCount-1; x>0; x--) {
results.deleteRow(x);
}
// This will populate the result table with the correct bus routes/times/direction
busArrivals.forEach(function(busArrival) {
var tr = document.createElement('tr');
var route = document.createElement('td');
route.appendChild(document.createTextNode(busArrival.ROUTE));
var arrival = document.createElement('td');
arrival.appendChild(document.createTextNode(busArrival.ARRIVAL));
var direction = document.createElement('td');
direction.appendChild(document.createTextNode(busArrival.DIR));
tr.appendChild(route);
tr.appendChild(arrival);
tr.appendChild(direction);
document.getElementById('results').appendChild(tr);
});
}
function getJSON(callback) {
var data = [{"ARRIVAL":"05:23P","ROUTE":"201","DIR":"E"},
{"ARRIVAL":"05:54P","ROUTE":"202","DIR":"E"},
{"ARRIVAL":"06:33P","ROUTE":"203","DIR":"E"},
{"ARRIVAL":"07:11P","ROUTE":"204","DIR":"E"}];
callback(data);
}
getJSON(makeTable);
};
I think you could write a separate function to build the table, like this:
function makeTable(busArrivals) {
busArrivals.forEach(function(busArrival) {
var tr = document.createElement('tr');
var route = document.createElement('td');
route.appendChild(document.createTextNode(busArrival.ROUTE));
var arrival = document.createElement('td');
arrival.appendChild(document.createTextNode(busArrival.ARRIVAL));
var direction = document.createElement('td');
direction.appendChild(document.createTextNode(busArrival.DIR));
tr.appendChild(route);
tr.appendChild(arrival);
tr.appendChild(direction);
document.getElementById('results').appendChild(tr);
});
}
var busArrivalAPI = 'http://blahblahblah/rtcTimes/'+ stopNumber;
$.getJSON(busArrivalAPI, makeTable);
In each iteration of the forEach loop, you construct a tr element, insert the tds and finally put the whole thing inside the DOM.
You're creating a TR element, but never appending it to the table. Instead, you're appending the TH elements directly to the table, which is invalid.
function getTimes(stopNumber) {
var busArrivalAPI = "http://blahblahblah/rtcTimes/" + stopNumber;
$.getJSON(busArrivalAPI, function(busArrivals) {
var table = document.getElementById('results');
for (var i = 0; i < busArrivals.length; i++) {
var a = [busArrivals[i].ROUTE, busArrivals[i].ARRIVAL, busArrivals[i].DIR];
var row = document.createElement("TR");
for (var b = 0; b < 3; b++) {
var x = document.createElement("TH");
var z = a[b];
var t = document.createTextNode(z);
x.appendChild(t);
row.appendChild(x);
};
table.appendChild(row);
};
});
}
I'm not sure why you need the a array. If you just want to change get the object properties into an array so you can iterate over it, you can do that with a 1-dimensional array, you don't need to save all the other rows in a 2-dimensional array. I've changed a to a single array.

Dynamically generating lists without document.write?

I'm using JavaScript to create a list of links from a text source. Using document.write(), resets/creates a new page which is not desirable. I do not know the amount of items in the list, so precomposing a list and using innerHTML to set values doesn't seem 'do-able' ? How would one go about generating dynamic lists in JS?
You can create elements dynamically by using document.createElement. It could work for example like this:
var container = document.getElementById('my-list'),
items = [],
addItem;
addItem = function (text) {
var elm = document.createElement('li');
elm.innerHTML = text;
container.appendChild(elm);
items.push(elm);
};
// generating random list
var i = 0,
j = Math.floor(Math.random() * 50);
for (i; i < j; i++) {
addItem('list item ' + i);
}
As Matti Mehtonen stated you can use document.createElement(), in order to create dynamically elements. One note on this is that instead of appending the newly created elements directly into a DOMnode, you should instead create a document fragment and append the elements to it, afterwards you append the fragment to the DOMnode. This way the process will be faster.
var items = ['cars', 'toys', 'food', 'apparel'];
function render(elementId, list) {
//getting the list holder by id
var el = document.getElementById(elementId);
//creating a new document fragment
var frag = new DocumentFragment();
//iterate over the list and create a new node for
//each list item and append it to the fragment
for (var i = 0, l = list.lenght; i < l; i++) {
var item = document.createElement('span');
frag.appendChild(item.innerHTML = list[i]);
}
//finally append the fragment to the list holder
el.appendChild(frag);
}
//rendering
render("my-list-holder", list);

Categories

Resources