Add id dynamically to each table cells - javascript

I am trying to create a dynamic js table and I want to give id to each cell dynamically. I want to use those ids to use in different js event handlers. How it can be done? I have tried in different ways but none of them works!
<html>
<head>
<style>
#colors {
float: right;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<script>
var d;
var k = 0;
function makeit() {
var tbl = document.createElement("table");
var atts = document.createAttribute("style");
atts.value = "border:1px solid black;text-align:center;padding:2px;margin:3px 3px 3px 3px;";
tbl.setAttributeNode(atts);
for (i = 0; i < 5; i++) {
var rows = tbl.insertRow(i);
for (j = 0; j < 7; j++) {
d = rows.insertCell(j);
d.height = "50px";
d.width = "50px";
d.style.backgroundColor = "yellow";
d.addEventListener("click", function myfunc() { d.style.backgroundColor = "red"; });
}
}
document.body.appendChild(tbl);
}
window.onload = makeit;
</script>
</body>
</html>

Just add
d.id = "r" + i + "c" + j;
under
d=rows.insertCell(j);
to set unique ids on each td.
Obviously, you can change the syntax r2c4 (which would be 3. row and the 5. cell) to your own liking.
If you want to call a function when clicking on a specific td you could even pass the row index (i) and column index (j) to that function.
Side note
You should consider using a JavaScript library or framework like jQuery for manipulations like this. It would facilitate your work a lot in the long term.

The problem is a scope issue. When adding the event listener, d's reference gets updated to be the last table cell you have created.
You can simply change the event listener's function to:
function myfunc() {
this.style.backgroundColor="red";
}
So that this references the object it is attached to. Depending on your intention, you may not need unique ids if you have access to the cell itself.

Using an approach that includes wongcode's solution, you may wish to consider the following code:
<html>
<head>
<style>
#myTbl{ border:1px solid black;text-align:center;padding:2px;margin:3px 3px 3px 3px; }
#myTbl td{ width: 50px; height: 50px; background-color: yellow;}
</style>
</head>
<body>
<script>
function onCellClicked(e)
{
this.style.backgroundColor = 'red';
}
function makeit()
{
var tbl=document.createElement("table");
tbl.id = 'myTbl';
var curCellIndex = 0;
for(i=0;i<5;i++)
{
var rows=tbl.insertRow(i);
for(j=0;j<7;j++)
{
d=rows.insertCell(j);
d.id = 'cell_' + curCellIndex;
curCellIndex++;
d.addEventListener("click",onCellClicked, false);
}
}
document.body.appendChild(tbl);
}
window.onload=makeit;
</script>
</body>
</html>
Some of the advantages include:
Smaller html file created in your editor
Smaller html code created in the browser
Use of context and the this keyword
Smaller memory consumption, since each TD doesn't contain the full
body of the event handler (it only include a 'pointer' to the
function to be executed)
EDIT: forgot to add code to give the cells an id. Now fixed.

Related

How would I make specific boxes changes color upon clicking on them?

I'd like to change color of more than one box to purple upon clicking on it. With my current code below, only one box gets colored purple when clicking on it.
I've tried so many different ways to make it work in terms of upon you clicking on any number of boxes, the box should turn purple, but all my attempts have failed.
What am I doing wrong?
function createBoxesDynamically() {
var tileLength = Math.floor(Math.random() * 11);
console.log("tileLength " + tileLength);
var box = new Array(tileLength);
console.log("box" + box);
for (var i = 0; i < box.length; i++) {
box[i] = "box";
}
for (var j = 0; j < box.length; j++) {
var div = document.createElement("div");
div.id = "box";
document.body.appendChild(div);
}
var boxes = document.querySelector("[id^=box]");
boxes.addEventListener("click", function () {
boxes.style.backgroundColor = "purple";
});
}
createBoxesDynamically();
#box {
border: 1px solid;
width: 50px;
height: 50px;
background-color: green;
}
You can't have multiple elements with identical id values, that's why no matter which box you click, the first one is always affected, your .querySelector() call stops looking after finding the first match.
Instead, move the code that sets up the event handler inside the loop where the box is being created and just use this in the click callback to have the callback act upon the box that was clicked. No id necessary. And, because you won't be using ids, you don't need your array or the first loop.
In general, stay away from coding solutions that rely on ids. Yes, they seem precise and easy to use at first, but what you'll find (and you already are) is that they create very brittle solutions that don't scale very well. There are many other ways of referencing and styling elements besides an id.
You should also try to avoid inline styling of elements (setting up styles directly on the style property) as this usually leads to duplication of code and therefore makes the code more difficult to read and maintain. Use CSS classes for as much as you can.
function createBoxesDynamically() {
var tileLength = Math.floor(Math.random() * 11);
console.log("tileLength " + tileLength);
for (var j = 0; j < tileLength; j++) {
var div = document.createElement("div");
div.classList.add("box"); // Add the CSS class to the element
div.addEventListener("click", function () {
this.classList.add("clickColor");;
});
document.body.appendChild(div);
}
}
createBoxesDynamically();
/* Use Classes instead of IDs */
.box {
border: 1px solid;
width: 50px;
height: 50px;
background-color: green;
}
.clickColor { background-color: #800080; }

How to change the value of an element using EventListener

In this program, I'm able to add inputs with a button but I need to show the length of each input as it changes. I'm able to get the length using an EventListener, but I'm not sure how to change the text value for any newly created buttons.
On line 12, you can see that I'm able to change the value successfully on the first input but I'm using an html variable. If you look at my addCell() function, you'll see that I have an element as a child of each node to keep track of the length of each input. I need to access that element in my change() function so I can set the event.target.value.length to the corresponding nodes child element.
I've tried using this, setting var x = this and I've tried using the event.target properties to find the corresponding node and even innerHTML.
var i = 0;
var count = 1;
var length = 2;
var chars = 0;
document.addEventListener('input', function (evt) {
change(evt);
});
function change(elem) {
var check = document.getElementById("first");
if (event.target == check) {
document.getElementById("len").innerHTML = event.target.value.length;
return;
}
// Here's where I'm stuck
}
function removeCell() {
if (count <= 1) {
alert("Illegal operation, the police have been notified.")
return;
}
var elem = document.getElementById('main');
elem.removeChild(elem.lastChild);
count = count - 1;
length = length - 1;
}
function addCell() {
var node = document.createElement('div');
node.innerHTML += length;
var inp = document.createElement('INPUT');
var size = document.createElement('size');
inp.setAttribute("type", "text");
node.appendChild(inp);
node.appendChild(size);
document.getElementById('main').appendChild(node);
count += 1;
length += 1;
i += 1;
}
#area {
width: 585px;
background-color: lightgrey;
color: black;
border-style: solid;
margin-left: auto;
margin-right: auto;
min-height: 100px;
height: auto
}
#texts {
width: 220px;
height: 50px;
border-style: solid;
}
body {
background-color: grey;
}
<div id="area">
<form id="main">
<pre><b> input </b> length</pre>
<span id="list">
1<input type="text" id="first"> <var id="len"></var>
</span>
</form>
<br />
<button onclick="addCell()">Add Cell</button>
<button onclick="removeCell()">Remove Cell</button>
<button onclick="sort()">Sort</button>
</div>
Since I'm able to use alert() to show me the correct length of each newly created input each time it changes, I know there's a way to access the "size" element I created to update it using event.target.value.length
Your problem is that you use a "global" input event listener and your change() function is not programmed to handle multiple input fields because in it you are querying known element ids first and len.
If you want to go with a global listener you have to tell your change() function how to access the new input and corresponding target fields.
An easier way is that you modify your addCell() function and attach an event listener to the input field that you are creating instead of using a global one. Thereby each input field holds its own event listener. Since both the input field and your size element, which displays the length of the input value, are created in the same scope you can use easily write the length to the corresponding size element.
inp.addEventListener('input', function(){
size.innerText = inp.value.length;
});
If you want this to work with your provided HTML you need to remove your first input field and call addCell() manually so that your initial input gets rendered.
Your code should then look like this (note: I set var count = 0; and var length = 1;):
var i = 0;
var count = 0;
var length = 1;
var chars = 0;
function removeCell() {
if (count <= 1) {
alert("Illegal operation, the police have been notified.")
return;
}
var elem = document.getElementById('main');
elem.removeChild(elem.lastChild);
count = count - 1;
length = length - 1;
}
function addCell() {
var node = document.createElement('div');
node.innerHTML += length;
var inp = document.createElement('INPUT');
var size = document.createElement('size');
inp.setAttribute("type", "text");
inp.addEventListener('input', function(){
size.innerText = inp.value.length;
});
node.appendChild(inp);
node.appendChild(size);
document.getElementById('main').appendChild(node);
count += 1;
length += 1;
i += 1;
}
addCell();
#area {
width: 585px;
background-color: lightgrey;
color: black;
border-style: solid;
margin-left: auto;
margin-right: auto;
min-height: 100px;
height: auto
}
#texts {
width: 220px;
height: 50px;
border-style: solid;
}
body {
background-color: grey;
}
<div id="area">
<form id="main">
<pre><b> input </b> length</pre>
<span id="list"></span>
</form>
<br />
<button onclick="addCell()">Add Cell</button>
<button onclick="removeCell()">Remove Cell</button>
<button onclick="sort()">Sort</button>
</div>
If HTML layout is planned out and is consistent you can use [name] attribute for form controls and .class or even just the tagName. Use of #id when dealing with multiple tags is difficult and unnecessary. Just in case if you weren't aware of this critical rule: #ids must be unique there cannot be any duplicate #ids on the same page. Having duplicate #ids will break JavaScript/jQuery 90% of the time.
To accessing tags by .class, #id, [name], tagName, etc. use document.querySelector() and document.querySelectorAll() for multiple tags.
To access forms and form controls (input, output, select, etc) by [name] or #id use the HTMLFormElement and HTMLFormControlsCollection APIs.
.innerHTML is destructive as it overwrites everything within a tag. .insertAdjacentHTML() is non-destructive and can place an htmlString in 4 different positions in or around a tag.
Event handlers and event listeners work only on tags that were initially on the page as it was loaded. Any tags dynamically added afterwards cannot be registered to listen/handle events. You must delegate events by registering an ancestor tag that's been on the page since it was loaded. This was done with delRow() since the buttons are dynamically created on each row (changed it because one delete button that removes the last row isn't that useful. ex. 7 rows and you need to delete 4 rows just to get to the third row).
Here's a breakdown of: [...ui.len] ui references all form controls .len is all tags with the [name=len]. The brackets and spread operator converts the collection of len tags to an array.
There's no such thing as <size></size>. So document.createElement('size') is very wrong.
const main = document.forms.main;
main.oninput = count;
main.elements.add.onclick = addRow;
document.querySelector('tbody').onclick = delRow;
function count(e) {
const active = e.target;
const ui = e.currentTarget.elements;
const row = active.closest('tr');
const idx = [...row.parentElement.children].indexOf(row);
const length = [...ui.len][idx];
length.value = active.value.length;
return false;
}
function addRow(e) {
const tbody = document.querySelector('tbody');
let last = tbody.childElementCount+1;
tbody.insertAdjacentHTML('beforeend', `<tr><td data-idx='${last}'><input name='txt' type="text"></td><td><output name='len'>0</output></td><td><button class='del' type='button'>Delete</button></td>`);
return false;
}
function delRow(e) {
if (e.target.matches('.del')) {
const row = e.target.closest('tr');
let rows = [...row.parentElement.children];
let qty = rows.length;
let idx = rows.indexOf(row);
for (let i = idx; i < qty; i++) {
rows[i].querySelector('td').dataset.idx = i;
}
row.remove();
}
return false;
}
body {
background-color: grey;
}
#main {
width: 585px;
background-color: lightgrey;
color: black;
border-style: solid;
margin-left: auto;
margin-right: auto;
min-height: 100px;
height: auto
}
tbody tr td:first-of-type::before {
content: attr(data-idx)' ';
}
<form id="main">
<table>
<thead>
<tr>
<th class='txt'>input</th>
<th class='len'>length</th>
<th><button id='add' type='button'>Add</button></th>
</tr>
</thead>
<tbody>
<tr>
<td data-idx='1'><input name='txt' type="text"></td>
<td><output name='len'>0</output></td>
<td><button class='del' type='button'>Delete</button></td>
</tr>
</tbody>
</table>
<!--These are dummy nodes because of the
HTMLFormControlsCollection API ability to use id or name, there
must be at least 2 tags with the same name in order for it to
be considered iterable-->
<input name='txt' type='hidden'>
<input name='len' type='hidden'>
</form>

For loop to fill my div box's

Confused on why this isnt filling my div box's with 1-28 please help.
$(document).ready(function () {
var $newdiv = $('div.box').text(i);
for (var i =2; i <28; i++) {
$newdiv = $('div.box').text(i);
$('div.box').append($newdiv);
}
});
You need to alter your conditions. Right now you are starting at i=2 and ending at i=27. Change your for-loop to do this instead:
for (var i=1; i<=28; i++) {
// ...
}
JavaScript objects are passed by reference. Therefore, you're changing the text of the original DOM object, not creating a new one. Try the following:
// Shorthand for $(document).ready(function () { ... });
$(function () {
// Create an array to store your new elements temporarily.
var newDivs = [];
for(var i = 1; i < 29; i++) {
// Create your new <div> elements and push them to
// your array. Using the following syntax for
// creating elements allows jQuery to use
// document.createElement internally.
newDivs.push($('<div />', { "class": "box", "text": i }));
}
// Once all elements are created, append the entire
// group to the $('div.box') element.
$('div.box').append(newDivs);
});
TRY this .It's tested.
<pre>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script>
$(document).ready(function () {
for (var i=1; i <28; i++) {
$('#box').append(i+" ");
}
});
</script>
</head>
<body>
<style type="text/css">
#box{
border: 1px solid red;
height: 100px;
width: 100px;
}
</style>
<div id="box">
</div>
</body>
</html>
<code>

Cant understand why doesn't this javascript work

<!DOCTYPE html>
<html>
<head>
<title>Anti Chess</title>
</head>
<body>
<h1 id="game_title">Anti Chess by theManikJindal</h1>
<br />
<br />
<table id="game"></table>
<script>
var white = 1;
var ta = document.getElementById("game");
if(white == 1)
{
for(var i=0;i<8;i++)
{
var x = document.createElement('tr');
ta.appendChild(x);
for(var j=0;j<8;j++)
{
var y = document.createElement('td');
ta.childNodes[i].appendChild(y);
ta.childNodes[i].childNodes[j].setAttribute("id",String.fromCharCode(j+97)+(8-i).toString());
}
}
}
else
{
for(var i=0;i<8;i++)
{
var x = document.createElement('tr');
ta.appendChild(x);
for(var j=0;j<8;j++)
{
var y = document.createElement('td');
ta.childNodes[i].appendChild(y);
ta.childNodes[i].childNodes[j].setAttribute("id",String.fromCharCode(104-j)+(i+1).toString());
}
}
}
</script>
</body>
</html>
I cannot understand why this script is not working. Are there any good debuggers for Javascript or does one have to keep on smashing their heads against the wall to make some sense.
Please help
The script is supposed to create a table with 8x8 boxes and the attribute id should be set from "a8","b8","c8"..."h8" to "a1","b1","c1"..."h1" . for a when the value of white is 1. And from "h","g1","f1"..."a1" to "h8","g8",..."a8" for white not equal to 1. white =1 is default for now.
Tables must always have at least one <tbody> element. If it does not, the browser will create one.
This means that your entire childNodes access is wrong.
I would suggest this HTML:
<table><tbody id="game"></tbody></table>
That should make your code work, but you can simplify it further:
var white = 1, a = "a".charCodeAt(0), i, j, x, ta = document.getElementById("game");
for(i=0;i<8;i++) {
x = document.createElement('tr');
for(j=0;j<8;j++)
x.appendChild(document.createElement('td')).id =
String.fromCharCode((white == 1 ? j : 8-j)+a)+(white == 1 ? 8-i : i+1);
ta.appendChild(x);
}
As you can see I have eliminated the need for the entire block of code to be repeated, by moving the white == 1 check to the most relevant place. I have also made more use of the x reference, and I have replaced the "magic" values with something that will be easier to understand when you come back to it later (the a variable).
Hope this helps!
EDIT: Also, I just noticed that the table has no content - is this what you mean by it not showing up? Make sure you have suitable CSS to make the table cells visible.
This script is working fine. I have inspcted element in jsfiddle and found that elements are created.
I have used some css to show that boxes have been created.
css
table{
border:1px solid black;
}
table tr, td{
border:1px solid black;
}
see here http://jsfiddle.net/9uHPx/
Java script is working but table is not display.
Add border=1 in Table
Script is working fine. Added a couple loops so the ID will print to in the td tag so you can see what's going on. http://jsfiddle.net/5YRKx/
var tableTemp = document.getElementById("game");
for (var ii = 0, row; row = tableTemp.rows[ii]; ii++) {
//iterate through rows
//rows would be accessed using the "row" variable assigned in the for loop
for (var j = 0, col; col = row.cells[j]; j++) {
row.cells[j].innerHTML = row.cells[j].id;
}
}

using buttons for changing font size for the whole website using javascript

i am trying to implement accessibility tools and i have managed to change the font size of a paragraph once the button has been clicked but i tried altering the code so that it will work on all the paragraph and it does not work
<script>
function myFunction()
{
var p =document.getElementsByTagName('p'); // Find the element
p.style.fontSize="1.5em"; // Change the style
}
</script>
<button type="button" style="background: #ccc url(images/small.jpg); padding: 0.3em 1em" onclick="myFunction()"></button>
this is how it worked before for just one paragraph but i am trying to more than one:
<script>
function myFunction()
{
x=document.getElementById("demo") // Find the element
x.style.fontSize="3.0em"; // Change the style
}
</script>
getElementsByTagName returns a NodeList, which is like an array, so you have to loop through them and apply the style to each element:
function myFunction() {
var arr = document.getElementsByTagName('p');
for (var i = 0; i < arr.length; i++) {
arr[i].style.fontSize = "1.5em";
}
}
Your issue in the first code block is that getElementsByTagName returns an nodeList of elements (which you can pretend is an array). So you would need to do this:
var p =document.getElementsByTagName('p'); // Find the element
for(var i=0; i<p.length; i++) {
p[i].style.fontSize="1.5em"; // Change the style
}
However, a better approach would be to define some css classes to do this job for you.
<style>
body { /*normal size*/
font-size: 1em;
}
body.largeFont {
font-size: 1.5em;
}
</style>
<script>
function largeFont() {
document.body.className="largeFont";
}
</script>

Categories

Resources