I'm making a react component for selecting and deselecting tags. For this is want the tags to be shown in a table, with a checkbox next to them.
My issue is that I can't set the text part of it, when creating them through JavaScript. Neither through innerHTML nor innerText. It shows in the inspector, but not in my browser (Chromium).
So far my method looks like this:
generateTagTable() {
let tbl = document.getElementById('tagTable')
tbl.className = 'tagTable'
let tbdy = document.createElement('tbody')
for (let i = 0; i < this.allTags.length; i++) {
let tr = document.createElement('tr')
let td = document.createElement('td')
let div = document.createElement('div')
let cb = document.createElement('input')
div.className = 'checkContainer'
cb.id = 'checkTd'
cb.type = 'checkbox'
cb.innerText = 'Tag'
div.appendChild(cb)
td.appendChild(div)
tr.appendChild(td)
tbdy.appendChild(tr)
}
tbl.appendChild(tbdy)
}
Which results in this:
I know that I can achieve my goal by doing the this:
generateTagTable() {
let tbl = document.getElementById('tagTable')
tbl.className = 'tagTable'
let tbdy = document.createElement('tbody')
for (let i = 0; i < this.allTags.length; i++) {
let tr = document.createElement('tr')
let td = document.createElement('td')
td.className = 'checkContainer'
td.innerHTML = '<div class="flexcenter"><input type="checkbox" name="tagCheck"/>' + this.allTags[i] + '</div>'
tr.appendChild(td)
tbdy.appendChild(tr)
}
tbl.appendChild(tbdy)
}
But that leaves me with problem when trying to assign the onClick, and generally leaves me with less control I feel.
The result of the working one is this, and what i'm trying to achieve is this:
Checkboxes (input elements in general) don't have content (they're void elements), so innerText and textContent and innerHTML don't have any function in relation to them.
If you want text next to your checkbox, the usual thing is to wrap a label around it. In markup, that would be:
<label>
<input type="checkbox">
Text
</label>
Adjusting your code, you might do:
// ...
let td = document.createElement('td')
let div = document.createElement('div')
let label = document.createElement('label') // *** (added)
label.innerText = 'Tag' // *** (moved and modified)
let cb = document.createElement('input')
div.className = 'checkContainer'
cb.id = 'checkTd'
cb.type = 'checkbox'
label.insertBefore(cb, label.firstChild); // *** (added)
div.appendChild(label) // *** (modified)
// ...
That said, it would be much simpler via markup (tr.innerHTML = ...), and browsers are very fast parsing markup.
// ...
let tr = document.createElement('tr')
tr.innerHTML = `
<td>
<div class="checkContainer">
<label>
<input type="checkbox" id="checkTd">
Tag
</label>
</div>
</td>`;
tbdy.appendChild(tr)
// ...
Side note: As it stands, your code creates multiple input elements with the same id (checkTd). That's invalid, only one element in a document can have that id. Depending on what you're doing, you may not need an id at all, or you may need to add a suffix to it (perhaps using i) to make it unique.
Related
Ok let's look at this part of the code -
$(tbody).find('tr').each((i, oldTbodyTr) => {
newTr = document.createElement('tr');
$(oldTbodyTr).find('td').each((i, oldTd) => {
let newTd = document.createElement('td');
newTd.innerHTML = oldTd.innerHTML;
newTd.classList = oldTd.classList;
newTd.style = oldTd.style; //Doesn't work
newTr.appendChild(newTd);
});
newTableTbody.appendChild(newTr);
});
It creates a new table body by looping through all rows in tbody of an already existing table.
Everything is fine, except that the style of the old td doesn't transfer to the new td element.
I can't figure out why.
If you want to copy inline styles, you could try newTd.style.cssText = oldTd.style.cssText since style itself is immutable.
See more about style.cssText.
const source = document.getElementById('source');
const target = document.getElementById('target');
target.style.cssText = source.style.cssText;
<p id="source" style="color: red; background-color: blue; font-size: 20px;">Source</p>
<p id="target">Target</p>
In the function below, I create cards that have a toggle button and remove button. However, when I try to access the buttons with a queryselector, I get null. Anyone know how to access elements that were created in a different file? I can provide the full files if needed.
function updateDisplay() {
for (i = 0; i < myLibrary.length; i++){
let div = document.createElement('div');
let title = document.createElement('h5');
let author = document.createElement('h5');
let pages = document.createElement('h5');
let isRead = document.createElement('h5');
let removeButton = document.createElement('button');
let toggleButton = document.createElement('button');
div.classList.add('card');
title.classList.add('title');
author.classList.add('author');
pages.classList.add('pages');
isRead.classList.add('isRead');
removeButton.classList.add('removeButton');
toggleButton.classList.add('toggleButton');
title.textContent = myLibrary[i].title;
author.textContent = myLibrary[i].author;
pages.textContent = `${myLibrary[i].pages} pages`;
isRead.textContent = myLibrary[i].isRead ? 'Read' : 'Unread';
removeButton.textContent = 'Remove';
toggleButton.textContent = 'Toggle Read Status';
Your problem is obvious you're creating the elements but not appending the into the body.
you'll have to append each element you create like the following example:
var element= document.createElement("div"); // Create a <div> element
element.innerHTML = "some content"; // Insert text
document.body.appendChild(element); // Append <div> to <body>
note that you can do document.body.append(div,title,author,pages,isRead,removeButton,toggleButton);
to append them all in one line
I am trying to do append() function. i have a table of data. i run a loop to first remove text in cell then i will append a new tag.this usecase is to create a progress bar. for an example
data sample inside cell is e.g 39% 39% 82% etc etc
let cf_percent;
let cf_regex;
for(let i = 0 ;i < tbl[0].length;i++){
cf_percent = tbl[0][i].innerHTML
cf_regex = cf_percent.replace(/[`~%]/gi, '');
console.log(cf_regex)
//Clear fields
tbl[0][i].innerHTML = ''
tbl[0][i].append('<p>Textfield</p>');
}
It should return texfield but instead, it is returning '<p> textfield </p>' in table cell.it should return textField. i have tried .html() but this does not work for this usecase.
in d3.js append function appends a new element with the specified name as the last child of each element in the current selection, returning a new selection containing the appended elements.
So to append p element use: tbl[0][i].append("p") and to set text use .text() further: e.g.
tbl[0][i].append("p").text("Textfield")
I will suggest to use:
let cf_percent;
let cf_regex;
for(let i = 0 ;i < tbl[0].length;i++){
cf_percent = tbl[0][i].innerHTML
cf_regex = cf_percent.replace(/[`~%]/gi, '');
console.log(cf_regex)
//Clear fields
tbl[0][i].innerHTML = ''
tbl[0][i].innerHTML += `<p>Textfield</p>`;
}
You have 2 options. The first is along what you are trying to do where you set the innerHTML to a string. The second is actually generating an element and then appending it. Your current scenario seems to be mixing the two.
const div1 = document.getElementById('sample1'),
div2 = document.getElementById('sample2'),
p = document.createElement('p');
div1.innerHTML = '<p>This set the innerHTML</p>';
p.innerText = 'This is a p appended to a div';
div2.appendChild(p);
#sample1 {
background-color: red;
}
#sample2 {
background-color: yellow;
}
<div id="sample1"></div>
<div id="sample2"></div>
I am doing some basic javascripting and am creating a 3 column table created by javascript sourced from an xml. The table is created by appending all the data in rows via javascript.
The first column has an input checkbox, created via javascript, that if ticked fetches a price from the third column on that row and adds all the prices of the rows selected to give a price total.
The problem I am having is I don't seem to be able to reference the appended information to obtain the information in the related price column (third column).
I have attached both the function I am using to create the table which is working and the function I am using to try and add it up which isnt working.
I found the following two articles Getting access to a jquery element that was just appended to the DOM and How do I refer to an appended item in jQuery? but I am using only javascript not jquery and would like a javascript only solution if possible.
Can you help? - its just the calculateBill function that isn't working as expected.
Thank you in advance
function addSection() {
var section = xmlDoc.getElementsByTagName("section");
for (i=0; i < section.length; i++) {
var sectionName = section[i].getAttribute("name");
var td = document.createElement("td");
td.setAttribute("colspan", "3");
td.setAttribute("class","level");
td.appendChild(document.createTextNode(sectionName));
var tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
var server = section.item(i).getElementsByTagName("server");
for (j=0; j < server.length; j++) {
var createTR = document.createElement("tr");
var createTD = document.createElement("td");
var createInput = document.createElement("input");
createInput.setAttribute("type", "checkbox");
createInput.setAttribute("id", "checkInput");
createTD.appendChild(createInput);
createTR.appendChild(createTD);
var item = server[j].getElementsByTagName("item")[0].innerHTML;
var createTD2 = document.createElement("td");
var createText = document.createTextNode(item);
createTD2.appendChild(createText);
createTR.appendChild(createTD2);
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
}
}
}
onload = addSection();
function calculateBill() {
var finalBill = 0.0;
var checkBox = document.getElementById("checkInput");
for (i=0; i < checkBox.length; i++) {
if (checkBox[i].checked) {
var parentTR = checkBox[i].parentNode;
var priceTD = parentTR.getElementsByTagName('td')[2];
finalBill += parseFloat(priceTD.firstChild.data);
}
}
return Math.round(finalBill*100.0)/100.0;
}
var button = document.getElementById("button");
button.onClick=document.forms[0].textTotal.value=calculateBill();
When you do x.appendChild(y), y is the DOM node that you are appending. You can reference it via javascript either before or after appending it. You don't have to find it again if you just hang on to the DOM reference.
So, in this piece of code:
var createInput = document.createElement("input");
createInput.setAttribute("type", "checkbox");
createInput.setAttribute("id", "checkInput");
createTD.appendChild(createInput);
createInput is the input element. You can reference it with javascript at any time, either before or after you've inserted it in the DOM.
In this piece of code:
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
You're creating a <td> element and putting a price into it. createTD3 is that particular <td> element.
If you want to be able to find that element sometime in the future long after the block of code has run, then I'd suggest you give it an identifying id or class name such that you can use some sort of DOM query to find it again. For example, you could put a class name on it "price" and then be able to find it again later:
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
createTD3.className = "price";
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
Then, you could find all the price elements again with:
tbody.querySelectorAll(".price");
Assuming tbody is the table where you put all these elements (since that's what you're using in your enclosed code). If the table itself had an id on it like id="mainData", then you could simply use
document.querySelectorAll("#mainData .price")
to get all the price elements.
FYI, here's a handy function that goes up the DOM tree starting from any node and finds the first node that is of a particular tag type:
function findParent(node, tag) {
tag = tag.upperCase();
while (node && node.tagName !== tag) {
node = node.parentNode;
}
return node;
}
// example usage:
var row, priceElement, price;
var checkboxes = document.querySelectorAll(".checkInput");
for (var i = 0; i < checkboxes.length; i++) {
// go up to the parent chain to find out row
row = findParent(checkboxes[i], "tr");
// look in this row for the price
priceElement = row.querySelectorAll(".price")[0];
// parse the price out of the price element
price = parseFloat(priceElement.innerHTML.replace(/^[^\d\.]+/, ""));
// do something here with the price
}
I have the following js code:
function createConBox() {
var charDiv = document.getElementById("characterList"); // reference to "characterList" div
header = document.createElement("p"); // creates the <p> tag
charDiv.appendChild(header); // adds the <p> tag to the parent node
title = document.createTextNode("Show Only Lines By:"); // creates the text string
header.appendChild(title); // adds the text string to the parent node
// create select box and add elements
selectBox = document.createElement("select");
selectBox.setAttribute("id", "cList");
charDiv.appendChild(selectBox);
charNames = uniqueElemText("h3"); // array of character names
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode("Show All Lines");
newOption.appendChild(newOptionTitle);
for (i = 0; i < charNames.length; i++) {
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode(charNames[i]);
newOption.appendChild(newOptionTitle);
}
}
function showLines() {
alert("The Box has been changed");
}
Every time the option in the box is changed, I want it to call 'showLines()'. However, every time I try to implement an event, I can only get it to trigger when the page loads, and never again thereafter.
selectBox.onchange = showLines; should solve your problem.
in some browsers onchange get fired only after blurring select box. to over come this you can use onclick instead of onchange
My guess is that you're doing this:
selectBox.onchange = showLines();
If that's the case, just remove the ():
selectBox.onchange = showLines;
When I pass dynamically id in case then what I do:
var selectcell = tablerow.insertCell(1);
var selectelmt = document.createElement('select');
selectelmt.name = 'Select';
selectelmt.value = 'select';
selectelmt.classList = 'form-control input-sm cobclass';
selectelmt.onchange= onselectchange(i);
selectelmt.id = 'cobselect' + i;
selectelmt.options[0] = new Option('select');
selectcell.appendChild(selectelmt);
// ddrbind(i);
show();
i++;`