Populating dynamic table row with dynamic select - javascript

I created a dynamic table using Javascript. I want to appendChild the cell of each row with a select.
First I tried it using it in a different populateTableCell function after the creation of table is finished. I thought it is better for code readability. But I couldn't succeed.
That's why I tried to populate it in the same function. However, it only populates the very last row.
<table id="informationTable">
<tr>
<th>userID</th>
<th>Status</th>
<th>Profile</th>
</tr>
</table>
Here is the JS I tried...
function setAllUsers(users){
//Create array of options to be added
var array = ["Normal","Incident","Major Incident"];
//Create select list
var selectList = document.createElement("select");
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
option.text = array[i];
selectList.appendChild(option);
}
for(i = 0; i < users.length-1; i++){
var table = document.getElementById('informationTable');
var row = document.createElement("tr");
row.id = users[i];
var cell0 = row.insertCell(0);
var cell1 = row.insertCell(1);
var cell2 = row.insertCell(2);
cell0.innerHTML = users[i];
cell0.value = users[i];
cell1.id=users[i]+"-status";
cell1.class="statusClass";
cell2.id=users[i]+"-profile";
cell2.class="profileClass";
cell2.appendChild(selectList);
table.appendChild(row);
}
}
I also tried putting the createElement('select'), createElement('option') and select.appendChild(option) inside the "for" loop. But this time page never loads.
I found a similar post and tried to use it.
How to dynamically insert a table row with a select box with options in a table using javascript?
But here each rows are appending due to button click.
Thanks for your answers.
Sincerely,
Alp

Few things:
It probably makes more sense to add a new column instead of appending into the profile cell, so you should add a new column header and run insertCell one more time
You should be using className, not class - class is a reserved word in Javascript.
Unless your users array contains HTML, you should use textContent instead of innerHTML for performance reasons.
You need to run selectList.cloneNode(true) when you append to the cell so that you get a new copy of the element each time.
It is expensive and pointless to run var table = document.getElementById('informationTable'); on each iteration of your loop, you only need to get that handle one time during your function's lifecycle - so move that to the top and outside your loop
I don't have your users array, but here is a working example with a guess on what your array might look like (feel free to replace let and const with var if you need to):
const users = [
['1', 'Active', 'Bob'],
['2', 'Disabled', 'Alice']
];
function setAllUsers(users){
//Create array of options to be added
const priorities = ["Normal","Incident","Major Incident"];
const table = document.getElementById('informationTable');
//Create select list
const selectList = document.createElement("select");
//Create and append the options
for (let i = 0; i < priorities.length; i++) {
const option = document.createElement("option");
option.value = priorities[i];
option.text = priorities[i];
selectList.appendChild(option);
}
for(let i = 0; i < users.length; i++){
const row = document.createElement("tr");
row.id = 'user-'+users[i][0];
const cell0 = row.insertCell(0);
const cell1 = row.insertCell(1);
const cell2 = row.insertCell(2);
const cell3 = row.insertCell(3);
cell0.textContent = users[i][0];
cell1.id = users[i][1]+"-status";
cell1.className = "statusClass";
cell1.textContent = users[i][1];
cell2.id=users[i][2]+"-profile";
cell2.className = "profileClass";
cell2.textContent = users[i][2];
cell3.appendChild(selectList.cloneNode(true));
table.appendChild(row);
}
}
setAllUsers(users)
<table id="informationTable">
<tr>
<th>userID</th>
<th>Status</th>
<th>Profile</th>
<th>Priority</th>
</tr>
</table>

Related

Javascript - Select option is adding to the next row in the table

I am making a dynamic table, where the inputs are coming from a mongo database. The fifth and final column contains a select option dropdown, where if the user clicks an option from the dropdown, the text value of that option will show in column 3. However, I designed my code to make sure that if that text value already exists in column 3 then don't add it again. However, for some strange reason, when the text value already exists in column 3, it decides to add it to the next row in column 3 instead. I am unsure as to why this is happening but I think it may be due to the fact that I am using a forEach loop with addEventListeners instead it. I have provided 2 images, one is before I add "Human Resources" again to row 1" and the second image is what happens after I click on Human Resources from the dropdown in row 1 again. Honestly, the code could be better, but I am new to JavaScript.
Any help would be greatly appreciated. Thanks.
Images:
HTML:
<table id="productivity-table">
<thead>
<tr>
<th>Resource</th>
<th>Productive Identity</th>
<th>Impact Area</th>
<th>Set Productive Identity</th>
<th>Set Impact Area</th>
</tr>
</thead>
<tbody>
<tr></tr>
</tbody>
</table>
Js:
//List containing all departments
var alldepts = [];
var departmentID = document.createElement('select');
//getDepartments();
//Run Functions
getResources();
var old_selected_val = [];
var select_id = 1;
//Get Resources and corresponding information and display it in a table
function getResources(){
//getDept();
getDepartments();
fetch("________", {
}).then(response => {
return response.json();
}).then(data => {
var table = document.getElementById("productivity-table");
for(var i=0; i < data.length; i++){
var row = table.insertRow(table.rows.length - 1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
cell1.classList.add("table-data");
cell2.classList.add("table-data");
cell3.classList.add("table-data");
cell1.innerHTML = data[i].name;
cell2.innerHTML = data[i].productive == 0 ? "No" : "Yes";
//Cell3 - Create ul and li
var impact_ul = document.createElement("ul");
var impact_li = document.createElement("li");
impact_li.innerHTML = data[i].entity;
impact_li.setAttribute("style", "list-style-type:none");
//Add delete button row
var delete_span = document.createElement("span");
delete_span.className = "delete";
delete_span.innerHTML = "×"
impact_li.appendChild(delete_span);
impact_ul.appendChild(impact_li);
cell3.appendChild(impact_ul);
//Cell4 - Create select dropdown for impact area
var cell4 = row.insertCell(3);
cell4.classList.add("table-data");
var impact_area = document.createElement('select');
impact_area.setAttribute("id", "impact-area");
let defaultOption = document.createElement('option');
defaultOption.text = 'Is it Productive?';
defaultOption.disabled = true;
impact_area.add(defaultOption);
impact_area.selectedIndex = 0;
var productive_array = ["Yes", "No"];
productive_array.forEach(item => {
var impact_option = document.createElement("option");
impact_option.text = item;
impact_option.value = item;
impact_area.appendChild(impact_option);
cell4.appendChild(impact_area);
})
//Cell5 - Create department dropdown
var dep_dropdown = document.createElement('select');
dep_dropdown.classList.add("dep_select");
select_id++;
//dep_dropdown.length = 0;
let dep_default = document.createElement('option');
dep_default.text = 'Select Department';
dep_default.disabled = true;
dep_dropdown.add(dep_default);
dep_dropdown.selectedIndex = 0;
var cell5 = row.insertCell(4);
alldepts.forEach(item => {
cell5.classList.add("table-data");
var dep_option = document.createElement("option");
dep_option.text = item;
dep_option.value = item;
dep_dropdown.appendChild(dep_option);
cell5.appendChild(dep_dropdown);
})
Department_Select("productivity-table", cell3, impact_ul, select_id);
deleteButton();
}
})
}
//Listen to department select option and update table accordingly
function Department_Select(table_id, cell, ul, classLength) {
var table = document.getElementById(table_id);
var numRows = table.rows.length;
var i, s = null, tr, td;
dep_select = document.querySelectorAll(".dep_select");
dep_select.forEach(select => {
//Get the inital select option value, to ensure the user is selecting a new value
select.addEventListener("mouseenter", function(e){
//Get table row number
var rowNumber = this.parentNode.parentNode.rowIndex;
//Store inital select option value to compare to a value that the user clicks on
old_selected_val[rowNumber-1] = select.value;
});
select.addEventListener("click", function(e){
//Get Table row number
var rowNumber = this.parentNode.parentNode.rowIndex;
//Get current option value, that the user clicked on
selected_val = select.value;
//Checks if department already exists or not
var Depexists = false;
//If it's a new value, and if it doesn't already exist, add it to column 3
if(selected_val != old_selected_val[rowNumber-1] && selected_val != "Select Department"){
//Check if selected department already exists in list
li_list = ul.getElementsByTagName('li');
for (var i = 0; i < li_list.length; i++){
//Each department has an &times x attached to it, it needs to be removed to get department name
li_item = li_list[i].innerText;
listed_dep = li_item.substring(0, li_item.length-1);
//Check selected department exists
if(selected_val == listed_dep){
Depexists = true;
}
}
//If department doesn't already exist on table, add the new department to column 3
if(Depexists == false){
//Create ul and li
var impact_li = document.createElement("li");
impact_li.innerHTML = selected_val;
impact_li.setAttribute("style", "list-style-type:none");
//Add delete button row
var delete_span = document.createElement("span");
delete_span.className = "delete";
delete_span.innerHTML = "×"
impact_li.appendChild(delete_span);
ul.appendChild(impact_li);
cell.appendChild(ul);
//Button Listen for potential delete
deleteButton();
//Set the selected department value to be the old department value selected, for new incoming selections.
old_selected_val[rowNumber-1] = selected_val;
}
}
});
});
}
It seems that you doesn't update ul's reference in select.addEventListener("click" function and it refers to its last reference it has been assigned, which is was the next row (in fact in the last row which has value in 3rd column).

javascript change color of a dynamically added row

I been doing a small script in HTA in which it reads info from text files and show the info on screen.
I have a table with a header row.
<table cellspacing="2" cellpadding="2" border="1" id="TablaResultados" style="font-size:10;">
<tr bgcolor="#cd0041" align="center" style="color:white;">
<th>Fecha</th>
<th>Id Evento</th>
<th>Tipo Evento</th>
<th>Ubicacion</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Comentarios</th>
</tr>
</table>
and in this table I add dynamically rows of the info I read using javascript
function AgregarFila(Datos) {
var table = document.getElementById("TablaResultados");
var ArrDatos = Datos.split("#");
var row = table.insertRow(1);
var LargoArreglo = ArrDatos.length;
for (var i = 0; i < LargoArreglo; i++){
var cell1 = row.insertCell(i);
cell1.innerHTML = ArrDatos[i];
cell1.style.backgroundColor = "#99cc00";
}
}
every N rows I need to clear the color of the rows to white, and I am using this
function TablaABlanco() {
var table = document.getElementById("TablaResultados");
var rows = table.getElementsByTagName("tr");
for (var i = 1; i < rows.length; i++) {
rows[i].style.backgroundColor = "#ffffff";
}
}
My issue is that it does not change the color of the rows. I know that the function TablaABlanco does work because if I run the for loop from zero it changes the color of the header of the previous table.
I believe I might need to check something else to validate the new rows but I have been googling with no luck.
The issue is that in AgregarFila, you set the each cell to have a background color. In TablaABlanco, you set the row to be white. The style on the cell will take priority and override the style you apply to the row.
So instead of changing each cell to have the background color, you change the row's background color when you add it.
function AgregarFila(Datos) {
var table = document.getElementById("TablaResultados");
var ArrDatos = Datos.split("#");
var row = table.insertRow(1);
row.style.backgroundColor = "#99cc00";
var LargoArreglo = ArrDatos.length;
for (var i = 0; i < LargoArreglo; i++){
var cell1 = row.insertCell(i);
cell1.innerHTML = ArrDatos[i];
}
}

Get value from input in a table

I have the following code:
function create_row() {
var table = document.getElementById("main_table");
var n = table.rows.length;
var m = table.rows[0].cells.length;
var row = table.insertRow(-1);
var cell = row.insertCell(0);
cell.innerHTML = n;
var cell = row.insertCell(1);
cell.innerHTML = "<input size=10>";
for (i=2; i<m; i++) {
var cell = row.insertCell(i);
cell.innerHTML = "<input size=4>";
}
}
function print_values() {
var table = document.getElementById("main_table");
for (i=1; i<table.rows.length; i++) {
console.log(table.rows[i].cells[1].innerHTML);
}
}
However, when I print values I get <input size="10">.
The problem is that when I create a row, I add manually some value to a table (in a webpage) and I want to print those values in a log. How can I access those values, but not html of the input?
I probably can assign an id to each input form and then access value keyword, but thought maybe it could suffice using table cells.
The input element is a child of the table cell. And you have to use .value to get the value of an input, not .innerHTML.
console.log(table.rows[i].cells[1].childNodes[0].value)
You want the insides of your input, so you'll have to select that input.
yourExistingSelector.querySelector("input").innerHTML
In your case:
table.rows[i].cells[1].querySelector("input").innerHTML

How to add an UpperCase function to each textbox in a dynamic table?

I am trying to create a dynamic table with textboxes but I want the textboxes to be converted to upper case every time I write.
Any ideas on how to do this??
Currently this is how I am doing the dynamic table:
var n = 1;
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
//element.onkeyup = function(){alert()};
cell.appendChild(element);
}
n++;
}
I was trying to do a document.getElementById(element.id).value.toUpperCase() but I am getting an error with a null value for the element.id
Any help is greatly appreciated!
If you're ok with a non JavaScript solution, you could apply this CSS to your inputs:
text-transform: uppercase;
That would make the text uppercase from the beginning...
Darkajax's solution, works, you can target it to inputs within a table with a specific ID
with
#tableid input
{
text-transform: uppercase;
}
I tested your code with the onkeyup function activated:
var n = 1;
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
element.onkeyup = function(){alert(element.id);};
cell.appendChild(element);
}
n++;
}
And that worked. However, it uses the last element.id computed for every call to the function... so, when I created one row of 3 cells, every time I typed into a cell, it would alert "102" regardless of which cell I typed in.
This is because the onkeyup function is dynamic. It is called on the keyup action - not set when the object is created. So it uses the element.id value that exists at the time of the action, not what it was when you passed it in the first time. I hope that makes sense.
I had this issue myself on a recent project. One solution is to create a separate function for the inner workings of the for loop as such:
var n = 1;
function createRow (n, i) {
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
element.onkeyup = function(){alert(element.id);};
return element;
}
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
element = createRow(n, i);
cell.appendChild(element);
}
n++;
}
This code alerts the correct element.id value.
EDIT: you can change the onkeyup() line to read:
element.onkeyup = function(){document.getElementById(element.id).value = document.getElementById(element.id).value.toUpperCase();};
And it should work as you want it to.
with jQuery it will be like
$('.yourClass').val($(this).val().toUpperCase());
or
$('#yourId').css({'text-transform' : 'uppercase'})

How to run this script correctly to display the table in runtime?

I am trying to display a table with data in runtime using script.
I called the script from table header. Is that possible to call a function from table header.
</HEAD>
<BODY>
<TABLE id="dataTable" width="350px" border="1" onload="start('dataTable');">
<TR>
<THEAD>
<TR>
<TH>Select</TH>
<TH>Id</TH>
<TH>Name</TH>
<TH>Age</TH>
<TH>Dept</TH>
<TH>Option</TH>
</TR>
</THEAD>
</TABLE>
</BODY>
</HTML>
The Script is
function start(dataTable) {
var data = new Array();
var id;
var name;
var age;
var dept;
data[0].id = "1";
data[0].name = "Tamil";
data[0].age = "23";
data[0].dept = "CSE";
data[1].id = "1";
data[1].name = "Tamil";
data[1].age = "23";
data[1].dept = "CSE";
data[2].id = "1";
data[2].name = "Tamil";
data[2].age = "23";
data[2].dept = "CSE";
for (var i = 0; i<data.length; i++)
{
var table = document.getElementById(tableID);
var rowCount = data.length;
var row = table.insertRow(rowCount);
//Check box
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "checkbox";
cell1.appendChild(element1);
//ID Column
var cell2 = row.insertCell(2);
cell2.innerText = data[i].id;
//Name Column
var cell3 = row.insertCell(3);
cell3.innerText = data[i].name;
//Age Column
var cell4 = row.insertCell(4);
cell3.innerText = data[i].age;
//Dept Column
var cell5 = row.insertCell(5);
cell5.innerText = data[i].dept;
//Button Column
var cell6 = row.insertCell(6);
var element2 = document.createElement("input");
element2.setAttribute("type", "button");
element2.setAttribute("id", "dataRow"+id);
element2.setAttribute("value", "Edit");
cell6.appendChild("element2");
}
}
The output is just the Headers. I cant get the data into table.
Thanks for suggestions in advance.
width="350px"
px is CSS. No px when using the HTML attribute.
onload="start('dataTable');"
There is no load event on <table>, this will never be called. Put a <script> element after the table to call the function.
var data = new Array();
For sanity, use [] array literal syntax:
var data= [
{id: 1, name: 'Tamil', age: 23, dept: 'CSE'},
...
];
var id; [and name etc.]
You never use these variables. Declaring vars has nothing to do with members of an object.
document.getElementById(tableID)
You called that variable dataTable not tableID.
cell2.innerText = data[i].id;
innerText is a non-standard IE extension. Consider using the standard textContent property first, if available, or just use plain old cell2.appendChild(document.createTextNode(data[i].id));, which is supported more widely than either.
element2.setAttribute("type", "button");
Never use getAttribute/setAttribute in an HTML document, there are bugs in it in IE. Instead use the DOM Level 2 HTML properties, which are easier to read anyway. element2.type= 'button';.
cell6.appendChild("element2");
That's a string, not the variable element2.
Just call your script in a <script> tag after </table>. Your script should be able to see the table elements because they're alreadyy loaded

Categories