I am trying to create a table width javascript and createElement().
My problem is that it does not set any background image (just plain white).
However, if I set the innerHTML of the to an image tag with same path, it works!
create : function () {
var tbody = document.createElement('tbody');
for(i in this.map) {
var tr = document.createElement('tr');
for(j in this.map[i]) {
var td = document.createElement('td');
var cell = this.map[i][j];
td.style.color = "red";
console.log("gfx/tile_"+this.backgrounds[cell]+".png");
td.style.backgroundImage = "url(gfx/tile_"+this.backgrounds[cell]+".png);";
td.innerHTML = "j";
tr.appendChild(td);
}
tbody.appendChild(tr);
}
this.gameDOMelm.appendChild(tbody);
}
I also have another problem that there's space between each ROW in the table.
Here's the DOM Element I'm appending to:
<table id="gameField" cellpadding="0" cellspacing="0"></table>
And the CSS
* {padding: 0; margin: 0;}
td {
min-width: 32px;
min-height: 32px;
width: 32px;
height: 32px;
}
These problems occur both in Chrome and FF # ubuntu 11.04.
No errors shows in javascript console.
jack
Try "url('gfx/tile_"+this.backgrounds[cell]+".png')" (with single quotes around the URL).
Related
Hello i am trying to append some strings from an array to an table. I want every array item to have its own tr element.
The things i have tried so far is this:
const body = document.body
const table = document.createElement('table')
const tr = document.createElement('tr')
const th = document.createElement('th')
const form = document.createElement('form')
const label = document.createElement('label')
table.innerHTML
body.append(table)
tr.innerHTML
table.append(tr)
const thText = ["ID", "First name", "Last name", "Email", "Phone number", "Actions"]
thText.forEach((text)=>{
th.innerHTML = text
tr.append(th);
})
When console.log(th) i get <th> Actions </th> 6 times. but the only thing that is rendered is Actions once.
Would love to get some help. Thanks :)
You're only creating one th element. You'd need to create one for each iteration, so, within the loop:
thText.forEach(text => {
const th = document.createElement('th')
th.innerHTML = text
tr.append(th)
})
There's a few different ways to do this. Here's an example of one way. This method does a few things differently then your example.
It creates and uses a thead element for proper table formatting.
It uses a basic for loop method.
It creates a new th element for each header label in the array, then it appends it to the tr element.
It uses textContent instead of innerHTML
const headerLabels = ["ID", "First name", "Last name", "Email", "Phone number", "Actions"]
const body = document.body
const table = document.createElement('table')
const thead = document.createElement('thead')
const tr = document.createElement('tr')
thead.append(tr)
table.append(thead)
body.append(table)
for (let i = 0; i < headerLabels.length; i++) {
let th = document.createElement('th')
th.textContent=headerLabels[i]
tr.append(th)
}
td, th {
border: 1px solid #ddd;
padding: 8px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #4CAF50;
color: white;
}
<body>
<script src="main.js"></script>
</body>
I'm trying to use JavaScript to create a table based off the amount of rows from one table and amount of columns from another. When doing this, I want to assign the table a couple div id's and a table class in order to have the generated table line up on the right side of my employee table.
My problem is, when I create the table in JavaScript this way, I lose the scroll bars for the x and y axis of the table and it appears below the employee table. Scrolling the table is then done with the window scroll instead of having the table set and scrollable itself. I'm still new to HTML and JavaScript and I can't seem to find where I'm going wrong on my own. Here's my code and a JSFiddle for clarification:
var rows = document.getElementById('dayRow').getElementsByTagName("td").length;
var cols = document.getElementById('employeeCol').getElementsByTagName("tr").length;
var myTable = document.createElement('table');
myTable.classList.add("tableTasks");
var tr1 = null;
var td1 = null;
var text1 = null;
for(let i = 0; i < rows; i++) {
tr1 = document.createElement('tr');
for(let j = 0; j < cols; j++) {
td1 = document.createElement('td');
text1 = document. createTextNode('cell');
td1.appendChild(text1);
tr1.appendChild(td1);
}
myTable.appendChild(tr1);
}
document.body.appendChild(myTable);
.tableTasks {
width:100%;
margin-top:5px;
empty-cells: show;
height:1000px;
line-height: 35px;
width: 100px;
}
#table-wrapper-tasks {
position: relative;
width:81%;
float:right;
}
#table-scroll-tasks {
overflow-x: scroll;
overflow-y: scroll;
max-height: 522px;
}
<div id="table-wrapper-tasks">
<div id="table-scroll-tasks">
</div>
</div>
I'm trying to get something like the image attached.
https://jsfiddle.net/kk05x1cg/#&togetherjs=8kJlzomlvg
I am relatively new to DOM manipulation with JS and html. Here I am having to build a 10 * 10 grid, with sequential numbers in each cells representing its text node. And the requirement is that, when I click on any cell in the grid, if its text node value is 5 or a multiple of 5, then the text node of this cell and also all other cells in the grid which are multiples of 5 should be replaced with a "**".
Here's my code till now, but I am just failing to implement the conditional replacement of the cell's text node value on a click event. And here's my jsfiddle
Many thanks in advance.
<html>
<head>
<meta charset="utf-8">
<title>Grid with random numbers</title>
<style>
#grid {
margin: 10px;
font-size: 1.25em;
}
table {
border-collapse: collapse;
border: 1px solid #7f7f7f;
}
td {
border: 1px solid #7f7f7f;
width: 50px;
height: 50px;
text-align: center;
}
</style>
</head>
<body>
<div id="grid"></div>
<script>
let totalRows = 10;
let cellsInRow = 10;
let min = 1;
let max = 100;
function drawTable() {
let cellNumber = 1;
let grid = document.getElementById('grid');
let tbl = document.createElement("table");
// Create rows in the table
for (var r = 0; r < totalRows; r++) {
let row = document.createElement("tr");
row.setAttribute('id', (r));
// In each row now create cells
for (var c = 0; c < cellsInRow; c++) {
let cell = document.createElement("td");
let cellText = document.createTextNode(cellNumber++);
let cellFillingStar = document.createTextNode("**");
// each cell should have its 'id' attribute set, as its corresponding cellText value
cell.setAttribute('id', (cellNumber - 1));
cell.appendChild(cellText);
row.appendChild(cell);
// Code to check that each cell got its 'id' attribute set, as its corresponding cellText value.
cell.addEventListener(
"click",
function(e) {
var id = e.target.id;
if (id % 5 == 0) {
$('.table').each(function() {
$(this).find('id').each(function() {
alert("Multiple of 5");
cell.appendChild(cellFillingStar);
})
})
}
},
false);
}
tbl.appendChild(row);
}
grid.appendChild(tbl);
}
window.onload = drawTable;
</script>
</body>
First of all there are some error in your script, like you're trying to loop on a .table object that doesn't exist, as table has no class.
I've tried to simplify it a little bit, using jquery.
the main snippet I've added is this one:
$( "#grid table tr td" ).on( "click", function(event) {
var id = event.target.id;
if (id % 5 == 0) {
$( "#grid table tr td" ).each(function( index ) {
if ($(this).text() % 5 == 0) {
$(this).text($(this).text()+'**');
}
});
}
});
where you assign the event to all td elements, and then, based on their content or id value, you change the text of all relevant td that are multiple of 5.
here is the full working example:
https://jsfiddle.net/xpvt214o/88139/
I have a function that dynamically creates DOM nodes to accomodate GPS JSON data from a server. As number of nodes increases, browser performance also
degrades. Is there any means to rewrite/tweak the function to improve performance? The simplified node creation part of the function works as shown below:
var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.appendChild(tbody);
for(var i = 0; i<3000;i++){
var tr = document.createElement('tr');
for(var j=0;j<50;j++){
var td = document.createElement('td');
td.style.backgroundColor="#a"+j%10+'c';
tr.appendChild(td);
}
tbody.appendChild(tr);
}
You might want to consider using some kind of Recyclable List.
Such lists recycle their elements by deleting DOM nodes that lie outside the viewport and recreating them when currently viewed.
Long story short - only currently-viewed DOM nodes exist in the DOM at any given time
Another technique is to use a fixed number of cells which you then fill with data according to where the user is scrolled
AFAIK there's no other way to go about this - naively creating 150,000 DOM nodes would completely decimate your scrolling performance
Some Examples
An example in pure JS
An example that's build on top of Polymer
Another example build on top of React
Here's how the pure JS example handles this:
Source: http://elliottsprehn.com/personal/infinite-scroll.html
<!DOCTYPE html>
<style>
* { box-sizing: border-box; }
ul, li { list-style-type: none; padding: 0; margin: 0; }
h1 { font-size: 1.2em; }
#infinite-list {
width: 300px;
border: 1px solid #ccc;
margin: 1em;
position: relative;
}
#infinite-list .scroll-view {
overflow-y: scroll;
height: -webkit-calc(20em + 2px);
}
#infinite-list ul {
position: absolute;
top: 0;
width: -webkit-calc(100% - 16px);
}
#infinite-list li {
height: 2em;
line-height: 2em;
padding-left: 1em;
border-bottom: 1px solid #ccc;
}
#infinite-list li:last-child {
border-bottom: none;
}
#infinite-list .scroll-view .spacer {
height: -webkit-calc(2em * 20000);
}
</style>
<h1>Infinite Scrolling with a fixed number of DOM nodes</h1>
<div id="infinite-list">
<div class="scroll-view">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="spacer"></div>
</div>
</div>
<script>
(function() {
function randRange(low, high) {
return Math.floor(Math.random() * (high - low)) + low;
}
function randPick(array) {
return array[randRange(0, array.length)];
}
// Randomly create a bunch of test data.
var tlds = ['.com', '.net', '.org', '.edu', '.co.uk'];
var domains = ['google', 'facebook', 'yahoo', 'apple', 'youtube', 'amazon'];
var data = [];
for (var i = 0; i < 20000; ++i) {
data.push(i + ' ' + randPick(domains) + randPick(tlds));
}
var list = document.querySelector('#infinite-list');
var listItems = document.querySelectorAll('#infinite-list li');
var scrollView = document.querySelector('#infinite-list .scroll-view');
var itemHeight = listItems[0].getBoundingClientRect().height;
var previous;
// Propagate scrolling with the mouse wheel.
list.onmousewheel = function(e) {
var delta = e.wheelDeltaY;
if (Math.abs(delta) < itemHeight) {
delta = itemHeight * (delta > 0 ? 1 : -1);
}
scrollView.scrollTop -= delta;
};
function update() {
var current = scrollView.scrollTop;
if (previous == current) {
webkitRequestAnimationFrame(update);
return;
}
previous = current;
var first = Math.ceil(current / itemHeight);
for (var i = 0; i < listItems.length; ++i) {
listItems[i].firstElementChild.textContent = data[first++];
}
webkitRequestAnimationFrame(update);
}
update();
})();
</script>
If you are not already, you might want to hide the element you are creating nodes in, and only show it at the end of your loop.
E.g. set display:none; on it while you are working on it, and then switch back to display:block; (or whichever it is) afterwards.
Update: Actually, you don't even need to hide it, though that's one way to do it. The cleaner way is to wait with adding your table to the document until you finish adding all nodes to it, and then only add it to the body afterwards.
var table = document.createElement('table');
var tbody = document.createElement('tbody');
for(var i = 0; i<3000;i++){
var tr = document.createElement('tr');
for(var j=0;j<50;j++){
var td = document.createElement('td');
td.innerHTML = "#a"+j%10+'c';
td.style.backgroundColor="#a"+j%10+'c';
tr.appendChild(td);
}
tbody.appendChild(tr);
}
table.appendChild(tbody);
document.body.appendChild(table);
It might help to enlist the browser's help by making a template for a single row, then cloning it repeatedly:
var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.appendChild(tbody);
// Make a template row once up front
var rowtemplate = document.createElement('tr');
for(var j=0;j<50;j++){
var td = document.createElement('td');
td.style.backgroundColor="#a"+j%10+'c';
tr.appendChild(td);
}
// Now clone it over and over instead of creating it piecemeal repeatedly
// Must pass true to ensure it clones whole tree, not just top level tr
for(var i = 0; i<3000;i++){
table.appendChild(rowtemplate.cloneNode(true));
}
Obviously, it depends on the browser internals whether this helps, but typically, the browser should be able to clone an existing node tree faster than manually creating each element from scratch.
The goal is to change the color of a cell when it is clicked. There is my js code below. As you can see I tried the style.backgroundColor, but only the right bottom cell changed it's color regardless the clicked cell.
var board = document.getElementById("tab"),
lvl1 = {rows: 5, cols: 5};
for(var i=0; i<lvl1.rows; i++){
var row=board.insertRow();
for(var j=0; j<lvl1.cols; j++) {
var cell = row.insertCell();
}
}
board.onclick = function(e) {
var cellIndex = e.target.cellIndex;
var rowIndexx = e.target.parentNode.rowIndex;
console.log(cellIndex + ".." + rowIndexx);
cell.style.backgroundColor = "red";
};
table { margin: 0 auto; }
td {
height: 20px;
width: 20px;
border: 1px solid;
cursor: pointer;
}
<table id="tab"></table>
Replace:
cell.style.backgroundColor="red";
with
e.target.style.backgroundColor="red";
This will set the background for whatever is clicked on, which will be your elements. The alternative is to keep a two-deminsional array around of your cells ( cell[row][column] ) that you can get the proper cell from using your indexes.