Set input to read only? - javascript

I am trying to build a grade book web app. I wanted to be able to edit the table cells to input grades, but I can't set it to readonly. What am I doing wrong?
I tried changing the code in the save button, but nothing works. I cant seem to get the input tags for some reason.Am I missing something? Is there another way to try to set the cells to readOnly? I tried getting the td tags, but that didn't work.
var myTable = document.getElementById("myTable");
var r = 0;
var c = 1;
function addRow() {
//insert a row
var row = myTable.insertRow(r);
//insert cells into a row
var cell = row.insertCell(0);
cell.innerHTML = "Students[i]";
r++;
}
function addColumn() {
//add new cell to each row
var allRows = document.getElementsByTagName("tr");
for (var i = 0; i < allRows.length; i++) {
row2 = allRows[i];
cell2 = allRows[i].insertCell(c);
cell2.innerHTML = "Puff";
}
}
function editCell() {
var allCells = document.getElementsByTagName("td");
for (var j = 0; j < allCells.length; j++) {
//clear text, then put in input box
allCells[j].innerHTML = "";
var myInput = document.createElement("input");
myInput.type = "text";
myInput.readOnly = false;
allCells[j].appendChild(myInput);
}
}
function saveData() {
//turn all inputs into readOnly
var allInputs = document.getElementsByTagName("td");
for (var k = 0; k < allInputs.length; k++) {
allInputs[k].id = "inpoot";
document.getElementById("inpoot").readOnly = true;
}
//document.getElementsByTagName("input").readOnly = true;
}
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<table id="myTable"></table>
<button onClick="addRow()">Students</button>
<button onClick="addColumn()">Days</button>
<button onClick="editCell()">Edit</button>
<button onClick="savaData()">Save</button>

HTML IDs must be globally unique within a document. Since you're setting the ID to inpoot for each one, then the getElementById call is always going to be selecting the same element. Also, these elements are the tds, not the inputs themselves.
Try changing your save function thusly:
function saveData(){
//turn all inputs into readOnly
document.querySelectorAll("td > input").forEach(input => {
input.readOnly = true;
});
}

Is there another way to try to set the cells to readOnly?
Use this :
JS :
var myInput = document.createElement("input");
myInput.classList.add("readOnly-input");
CSS :
.readOnly-input{ pointer-events: none; }
The user can't interact when pointer-events are set to none. Let me know if you need more explaination.

Related

Why can't I total up these values?

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.

JS filter multiselect array only returns last elem

I am building a historical dash (currently with fake data due to security) and I have the multi select list that gens the first name of the person in alphabetic order. Now when selecting one name it regens the table with said name. When I select multiple names, it regens the table with the "lowest" alphabetical name. I cant figure out why my filter function is not building the new array with all selected names that are true in the "selected" statement. However I used the push() function and that works but only shows the first name. Any help would be awesome, I am new to JS and working with DOM is really fun!
histData is the main array with all info,
fNameArr is the re populated array from the filter method given the multi selections
Here is my js:
function mSelList(){
var selName = document.getElementById("jomax");
var fNameArr;
for(i=0; i<selName.length;i++){
let currentName = selName[i];
if(currentName.selected == true){
let fName = currentName.value;
fNameArr = histData.filter(function(data){
return data.first_name == fName;
});
}
}
function createTable(){
var col = [];
for (var i = 0; i < fNameArr.length; i++) {
for (var key in fNameArr[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
// create table section with css filters
var table = document.createElement("table");
table.setAttribute("class", "table is-hoverable is-bordered is-narrow");
table.setAttribute("id", "table");
var tr = table.insertRow(-1);
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th");
th.setAttribute("class", "is-uppercase is-size-7"); // attributes
th.innerHTML = col[i];
tr.appendChild(th);
}
for (var i = 0; i < fNameArr.length; i++) {
tr = table.insertRow(-1);
for (var j = 0; j < col.length; j++) {
var tabCell = tr.insertCell(-1);
tabCell.innerHTML = fNameArr[i][col[j]];
}
}
var tblSec = document.getElementById("tableSec");
tblSec.innerHTML = "";
tblSec.appendChild(table);
}
createTable();
}
You are using getElementById and running a loop over it? getElementById will return one specific element not a list of element. Here is mdn_link for more info.
var selName = document.getElementById("jomax");
I would suggest to use class instead.

How do I check if a cell has a select element in a Javascript loop?

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");

How can I get the text of a JavaScript-generated input element?

I have a table that creates a row of input elements each time the "+" button is clicked underneath it. All elements are given the className "table-data". Once the "Done" button is clicked I want to loop through all these elements and get the text inside of them:
<table id="myTable"></table>
<button onclick="addRow();">+</button>
<button onclick="getData();">Done</button>
function addRow() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
cell1 = row.insertCell(0);
cell1.innerHTML = '<input type="text"></input>';
cell1.className = 'table-data';
cell2 = row.insertCell(1);
cell2.innerHTML = '<input type="text"></input>';
cell2.className = 'table-data';
}
function getData() {
inputCells = document.getElementsByClassName("table-data");
for (var i = 0; i < inputCells.length(); i++) {
console.log(inputCells[i].innerHTML);
}
}
However, when I run this code it just logs: 'input type="text"'
I tried using this instead:
console.log(inputCells[i].value);
But this method just logs "undefined". How can I get the value of these input elements?
Note: I don't mind if jQuery is used to answer this question.
I've prepared a solution for you using jQuery as your question is tagged with it. My solution find all inputs in table and then iterates over them using jQuery#each method.
const $table = $('#myTable');
$('#addBtn').on('click', function() {
let tr = $('<tr>');
let td1 = $('<td>');
let td2 = $('<td>');
let input = $('<input>', {
type: 'text',
class: 'table-data'
});
td1.append(input.clone());
td2.append(input.clone());
tr.append(td1);
tr.append(td2);
$table.append(tr);
});
$('#doneBtn').on('click', function() {
$table.find('input').each(function() {
console.log($(this).val());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable"></table>
<button id='addBtn'>+</button>
<button id='doneBtn'>Done</button>
Details commented in demo
// Reference form
const form = document.forms[0];
/*
//A Pass a number (max 10)
//B Reference table
//C Number of cells in a row
//D if number of cells in a row is less than input number...
//E Run addCols() function
//F Number of cells in a row is equal to number of the input
//G Add row
//H On each iteration...
//I Add a cell
//J Create an input assign type and name
//K Add input to cell.
*/
function addRow(count) {//A
const table = document.querySelector("table");//B
let width = table.rows[0].cells.length;//C
if (width < count) {//D
addCols(table, width, count);//E
width = count;//F
}
const row = table.insertRow();//G
for (let r = 0; r < width; r++) {//H
const cell = row.insertCell();//I
const text = document.createElement('input');//J
text.name = 'data';
text.type = 'text';
cell.appendChild(text);//K
}
return false;
}
// Similar to addRow() but will only adds cells
function addCols(table, width, count) {
let rowCount = table.rows.length;
for (let r = 0; r < rowCount; r++) {
let row = table.rows[r];
for (let c = 0; c < (count - width); c++) {
let cell = row.insertCell();
let text = document.createElement('input');
text.type = 'text';
text.name = 'data';
cell.appendChild(text);
}
}
return false;
}
/*
//A Pass Event Object
//B Prevent the form from sending data to a browser
//C Collect all form controls and convert collection into array
//D Use flatMap() to filter in the inputs with text and extract it
*/
function getData(event) {//A
event.preventDefault();//B
const ui = [...this.elements];//C
let txt = ui.flatMap(field => field.matches('[name=data]') && field.value !== '' ? [field.value] : []);//D
console.log(txt);
return txt;
}
//Register the button to click event
form.elements.add.onclick = function(event) {
const qty = Number(event.target.previousElementSibling.value);
addRow(qty);
};
//Register the form to submit event
form.onsubmit = getData;
input {display:inline-block;font:inherit;width:10vw}
<form>
<input id='qty' type='number' min='0' max='10' value='2'>
<button id='add' type='button'>+</button>
<button type='submit'>Done</button>
<table><tr></tr></table>
</form>

Could you please help me to highlight the selected HTML table row created dynamically through java script

Below is the JavaScript functionalities addRow() I have used to add the rows dynamically and now am trying to highlight the selected row with red color using rowhighlight() function.
/Function to addRows dynamically to the HTML table/
function addRow(msg)
{
var table = document.getElementById("NotesFinancialSummary");
var finSumArr1 = msg.split("^");
var length = finSumArr1.length-1;
alert("length"+ length);
for(var i=1; i<finSumArr1.length; i++)
{
var rowValues1 = finSumArr1[i].split("|");
tb=document.createElement("tbody");
var tbody=document.createElement("tbody");
table.appendChild(tbody);
var tr=document.createElement("tr");
tbody.appendChild(tr);
for(var k=0;k<=10;k++)//adding data to table dynamically
{
var td=document.createElement("td");
tr.appendChild(td);
var element1=rowValues1[k];
td.innerHTML =element1;
tr.onclick=function(){
rowhighlight(this);//calling the rowhighlight function
}
}
}
}
function rowhighlight(x)
{
var index = x.rowIndex;
document.getElementById("NotesFinancialSummary").rows [index].style.backgroundColor = "red";
}
One approach is to first loop through the other rows and remove the styling (really should be a class) then apply the styling (again, class) to the selected row.
Here's one way of doing it:
function rowHighlight() {
var selectedRows = document.getElementsByClassName('selected');
for (var n = 0; n < selectedRows.length; n++) {
selectedRows[n].className = '';
}
this.className = 'selected'
}
And here's a working example of it, though very simple: fiddle time!

Categories