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 × 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).
Related
I need help creating a combo-box in my js file for the timesheet application? So there is an add row button in the timesheet which will create a new Row. I would like to have a drop-down + input for the first column in the row which will list the customers. Initially, there is no row in the timesheet application user will need to add a row to submit the timesheet. After clicking the add row it will create a row in which I would like to have a drop-down in the "Project Code" section which lists Internal Timesheet Application our customers. The JS code I used to create the table is as follows:
var arrHead = new Array(); // array for header.
arrHead = ['', 'Project Code', 'Project Description', 'Billable Hours'];
// first create TABLE structure with the headers.
function createTable() {
var empTable = document.createElement('table');
empTable.setAttribute('id', 'empTable'); // table id.
var tr = empTable.insertRow(-1);
for (var h = 0; h < arrHead.length; h++) {
var th = document.createElement('th'); // create table headers
th.innerHTML = arrHead[h];
tr.appendChild(th);
}
var div = document.getElementById('cont');
div.appendChild(empTable); // add the TABLE to the container.
}
//Creating a drop-downlist for Project Code
// now, add a new to the TABLE.
function addRow() {
var empTab = document.getElementById('empTable');
var rowCnt = empTab.rows.length; // table row count.
var tr = empTab.insertRow(rowCnt); // the table row.
tr = empTab.insertRow(rowCnt);
for (var c = 0; c < arrHead.length; c++) {
var td = document.createElement('td'); // table definition.
td = tr.insertCell(c);
if (c == 0) { // the first column.
// add a button in every new row in the first column.
var button = document.createElement('input');
// set input attributes.
button.setAttribute('type', 'button');
button.setAttribute('value', 'Remove');
// add button's 'onclick' event.
button.setAttribute('onclick', 'removeRow(this)');
td.appendChild(button);
}
else {
// 2nd, 3rd and 4th column, will have textbox.
var ele = document.createElement('input'); //I would like create a combo-box for 2nd Column
ele.setAttribute('type', 'text');
ele.setAttribute('value', '');
td.appendChild(ele);
}
}
}
// delete TABLE row function.
function removeRow(oButton) {
var empTab = document.getElementById('empTable');
empTab.deleteRow(oButton.parentNode.parentNode.rowIndex); // button -> td -> tr.
}
// function to extract and submit table data.
function submit() {
var myTab = document.getElementById('empTable');
var arrValues = new Array();
// loop through each row of the table.
for (row = 1; row < myTab.rows.length - 1; row++) {
// loop through each cell in a row.
for (c = 0; c < myTab.rows[row].cells.length; c++) {
var element = myTab.rows.item(row).cells[c];
if (element.childNodes[0].getAttribute('type') == 'text') {
arrValues.push("'" + element.childNodes[0].value + "'");
}
}
}
// The final output.
document.getElementById('output').innerHTML = arrValues;
}
//console.log (arrValues); // you can see the array values in your browsers console window. Thanks :-)
Here is the solution to my Problem:
To make a combo-box for only one column
// now, add a new to the TABLE.
function addRow() {
var empTab = document.getElementById('empTable');
var rowCnt = empTab.rows.length; // table row count.
var tr = empTab.insertRow(rowCnt); // the table row.
tr = empTab.insertRow(rowCnt);
for (var c = 0; c < arrHead.length; c++) {
var td = document.createElement('td'); // table definition.
td = tr.insertCell(c);
if (c == 0) { // the first column.
// add a button in every new row in the first column.
var button = document.createElement('input');
// set input attributes.
button.setAttribute('type', 'button');
button.setAttribute('value', 'Remove');
// add button's 'onclick' event.
button.setAttribute('onclick', 'removeRow(this)');
td.appendChild(button);
}
**else if (c==1) {**\\ Defining the first column with a drop-down
var values = ["","Tiger", "Dog", "Elephant"];
var select = document.createElement("select");
select.name = "pets";
select.id = "pets";
for (const val of values) {
var option = document.createElement("option");
option.value = val;
option.text = val.charAt(0).toUpperCase() + val.slice(1);
select.appendChild(option);
}
td.appendChild(select);
}
else{
// 3rd and 4th column, will have textbox.
var ele = document.createElement('input');
ele.setAttribute('type', 'text');
ele.setAttribute('value', '');
td.appendChild(ele);
}
}
}
I am building a gradebook web app. I wanted the app to have the ability to calculate grades upon pushing the Final button. However, it's not working for some reason:
var myTable = document.getElementById("myTable");
var r = 0;//how many rows; row index
var c = 1;//how many columns
//make a table
//table must be able to add rows
//table cells should be editable
//save changes?
//
//make a table head row
//all table columns must have a table head
//**
// var firstRow= myTable.insertRow(0);
function addRow(){
//make a new row
var row = myTable.insertRow(r);
//use a while loop to keep creating row cells until you reach last column
var i = 0;
while(i<c){
var cell = row.insertCell(i);
cell.innerHTML ="Students[i]";
i++;
}
r++;
}
function addColumn(){
//make new column
//increment column
var tHead = document.createElement("th");
var allRows= document.getElementsByTagName("tr");//get all rows
//put tHead in first row
allRows[0].append(tHead);
var dateTable = document.createElement("input");
dateTable.type = "date";
tHead.appendChild(dateTable);
//tHead.innerHTML = (c*2);
//add a new cell for each row
var j =1;
while(j<allRows.length){
var row2 = allRows[j];
var cell2 = row2.insertCell(c);
cell2.innerHTML = j;
j++;
}
c++;
f++;
//if there already id a final row, delete it
}
function unEdit(){
//go through every cell
//save input value to a variable
//remove the input cell
var valArray =[];
document.querySelectorAll("td>input").forEach(input => {
var num = parseInt(input.value);
valArray.push(num);
input.remove();
});
//put input value into innerhtml of td
var i = 0;
document.querySelectorAll("td").forEach(td =>{
td.innerHTML=valArray[i];
i++;
});
}
function editTable(){
var allCells = document.getElementsByTagName("td");
for(var k=0; k<allCells.length; k++){
var oldText= allCells[k];
var input = document.createElement("input");
input.type ="number";
input.max = 100;
input.min = 0;
//before making all cells input, save previous innerhtml to var,
//make it into a num instead of a string, and put that value into input
var prev = allCells[k].innerHTML;
prev = parseInt(prev);
input.value = prev;
allCells[k].innerHTML = "";
allCells[k].appendChild(input);
input.onblur;
}
}
function deleteRow(){
document.getElementById("myTable").deleteRow(1);
r--;
}
function deleteColumn(){
//go through each row
//delete cell at each index
var everyRow = document.getElementsByTagName("tr");
for(var p=0; p<everyRow.length; p++){
everyRow[p].deleteCell(-1);
}
c--;
var finalButton = document.getElementById("final");
finalButton.enabled = true;
}
//final grade column
function finalRow(){
//make a <thead>
//make a new cell going down
var finalHead = document.createElement("th");
finalHead.innerHTML= "Final Grade";
var theseRows = document.getElementsByTagName("tr");
theseRows[0].append(finalHead);
for(var t =1; t<theseRows.length; t++){
//go through every cell in the row
//total up the numbers and put it in the final cell
var finalTotal=0;
for(var e =1; e< theseRows[t].length; e++){
var numero = theseRows[t][e].value;
numero = parseInt(numero);
console.log(numero);
finalTotal += numero;
}
//add up the innerhtmls and put it in finalCell
var finalCell = theseRows[t].insertCell(-1);
finalCell.innerHTML = finalTotal;
}
c++;
//disable final button
var finalButton = document.getElementById("final");
finalButton.disabled = true;
var days = document.getElementById("days");
days.disabled = true;
}
addRow();
addColumn();
//make a table head row at the top
//maybe add a print button?
//add a final grade column
//make it so that final row stays final when add new students and days
//do final funtion inside of unEdit() at the end?????
table,td,th{
border: 1px solid black;
border-collapse: collapse;
}
<table id = "myTable"></table>
</script>
<button onclick ="addRow()">Students</button>
<button onclick ="addColumn()" id ="days">Days</button>
<button onclick="editTable()">Edit</button>
<button onclick="unEdit()">Unedit</button>
<button onclick="deleteRow()">Delete Row</button>
<button onclick="deleteColumn()">Delete Column</button>
<button onclick ="finalRow()" id ="final">Final</button>
<button>Print</button>
In the finalRow() function, I can't figure out why the total I keep getting is always 0. Why doesn't it add up the value of the cells? I wanted it to go through every row, get the number values from each cell and total it up. It seems like the issue is with the "numero" variable, but I'm not sure what the issue is.
the first error is because you forgot to declare the variable f, you declared only the variables r and c above.
the second is in the function DeleteRow() there is an indexing error because it finds a negative value when deleting the last row. If you don't even want him to delete the last row, I suggest using a Try-Catch to deal with this error.
I have a dynamically created table which is generated through a JS addRow function. I would like to loop through this table and check if the cell has a select element in it. If it does then I would like to push the value of the selected option to a dictionary called ingredient_dict.
This is what I have so far:
var table = document.getElementById('selected_ingredients');
var rowCount = table.rows.length;
//table width by counting headers minus the last cell which has a delete button
var cellsCount = table.rows[0].cells.length -1 ;
//loop through all rows (r) in table
for (var r = 1; r < rowCount; r++) {
//initiate dictionary for this ingredient
var ingredient_dict = {};
//loop through each cell (c) in row
for (var c = 0; c < cellsCount; c++) {
var $cell = table.rows[r].cells[c];
if (**CHECK IF CELL HAS A SELECT ELEMENT**) {
$ingredient_dict["UOM"] = $cell.options[$cell.selectedIndex].value
} else if (**CHECK IF CELL HAS INPUT ELEMENT**) {
$ingredient_dict["qty"] = $cell.value
} else {
$ingredient_dict["name"] = $cell.value
}
}
}
I'm not sure if it matters but this is the code in my addRow function to dynamically create the select element:
// ingredient unit of measurement drop down
var cell3= row.insertCell(2);
var unit_of_measure = document.createElement("select");
unit_of_measure.name = "unit_of_measure_select";
cell3.appendChild(unit_of_measure);
I'm pretty new to javascript so I apologize if my code is messy or if this is an obvious question!
var doesCellHaveElement = (cell,element) => {
return cell.innerHTML.toLowercase().indexOf(`<${element}`) >= 0;
};
element would be some name of tag in lowercase. For example:
doesCellHaveElement(cell, "select");
doesCellHaveElement(cell, "input");
I've been attempting to fetch user input value from input fields to later on set it into a summary table that creates cells using javascript but can't seem to get it to work.
Following is my code:
function summonTable(f) {
var sLoc = f.countryf.value();
var eLoc = f.countryt.value();
var sDate = f.sdate.value();
var eDate = f.edate.value();
var div = document.getElementById("summary");
var magicTable = document.getElementById('summaryTable').querySelectorAll('tbody tr'),
var row = document.createElement('tr');
var th = document.createElement('th');
th.textContent = sDate;
var td = document.createElement('td');
td.textContent = sLoc;
//To state which row and column this cell goes to.
row.appendChild(th);
div.appendChild(magicTable);
});
The function summonTable will take in the arguement form f that contains the input fields, I've tried basic textboxes, checkboxes, radios, but all to no avail. The variables sLoc, eLoc are basically texts for countries and sDate, eDate are supposed to be dates.
function summonTable(f) {
var sLoc = f.countryf.value();
var eLoc = f.countryt.value();
var sDate = f.sdate.value();
var eDate = f.edate.value();
var div = document.getElementById("summary");
// to get the last row of the table
var magicTable = document.getElementById('summaryTable').querySelectorAll('tbody tr:last-child'),
var row = document.createElement('tr');
var th = document.createElement('th');
th.textContent = sDate;
var td = document.createElement('td');
td.textContent = sLoc;
//To state which row and column this cell goes to.
row.appendChild(th);
magicTable.after(row); //To add the row after the last row
div.appendChild(magicTable);
});
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>