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 am trying to create an excel-like table to update and log things on the go.
I have found this javascript:
function init()
{
var tables = document.getElementsByClassName("editabletable");
var i;
for (i = 0; i < tables.length; i++)
{
makeTableEditable(tables[i]);
}
}
function makeTableEditable(table)
{
var rows = table.rows;
var r;
for (r = 0; r < rows.length; r++)
{
var cols = rows[r].cells;
var c;
for (c = 0; c < cols.length; c++)
{
var cell = cols[c];
var listener = makeEditListener(table, r, c);
cell.addEventListener("input", listener, false);
}
}
}
function makeEditListener(table, row, col)
{
return function(event)
{
var cell = getCellElement(table, row, col);
var text = cell.innerHTML.replace(/<br>$/, '');
var items = split(text);
if (items.length === 1)
{
// Text is a single element, so do nothing.
// Without this each keypress resets the focus.
return;
}
var i;
var r = row;
var c = col;
for (i = 0; i < items.length && r < table.rows.length; i++)
{
cell = getCellElement(table, r, c);
cell.innerHTML = items[i]; // doesn't escape HTML
c++;
if (c === table.rows[r].cells.length)
{
r++;
c = 0;
}
}
cell.focus();
};
}
function getCellElement(table, row, col)
{
// assume each cell contains a div with the text
return table.rows[row].cells[col].firstChild;
}
function split(str)
{
// use comma and whitespace as delimiters
return str.split(/,|\s|<br>/);
}
window.onload = init;
And it seems like it will work well in saving and keeping the edits in the table.
The issue is, however, that I am using pycharms and - unfortunately - cannot use a js file within mine.
Is there a way to convert this to Python, or a way to code a table within Python?
I am JavaScript/html beginner and currently I am dealing with following issue:
I have several input fields, which are filled by the user.
When he filled up the fields, he presses the button and several tables are created.
So far works everything fine.
BUT
If I update the information in the input field and press the button, the NEW tables are created (the previous tables stay and new are added below)
My idea was to make following:
I put the new tables in a separate div.
Every time I press the button, the div information is deleted and created again.
But as I am a beginner I don’t really know how to do it.
Can anyone help me?
Do you have a better idea?
My code
(...)
/part with the table creation/
var zaehler=0;
for (zaehler = 0; zaehler < n; zaehler++){
tableCreate(n,zaehler,a,b,c,d,e,f,g,h,i,j,k,l);
}}
/the table create function/`
<script>
function tableCreate(maxyear,s4italka, a,b,c,d,e,f,g,h,i,j,k,l) {
var imena = ["Выручка", "Управляющая кампания", "Профилактика", "Налог на Недвижимость", "Страховка", "Амортизация", "Тело кредита", "%-ные выплаты банку", "%-ные выплаты себе", "Доход",
"Налог (15%)", "Финансовый результат" ];
var dannie =[a,b,c,d,e,f,g,h,i,j,k,l];
var body = document.getElementsByTagName('body')[0];
var tbl = document.createElement('table');
tbl.style.width = '40%';
tbl.setAttribute('border', '1');
var tbdy = document.createElement('tbody');
var trh = document.createElement('tr');
var th = document.createElement('th');
var m=s4italka+2015;
th.appendChild(document.createTextNode('Результат на '+m+ ' год'))
th.setAttribute ('colSpan','2');
trh.appendChild(th)
tbdy.appendChild(trh);
for (var i = 0; i < 12; i++) {
var tr = document.createElement('tr');
for (var j = 0; j < 2; j++) {
var td = document.createElement('td');
if ((j % 2) != 0)
{td.appendChild(document.createTextNode(dannie[i]))}
else {
td.appendChild(document.createTextNode(imena[i]))}
tr.appendChild(td)
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
body.appendChild(tbl)
var p= document.createElement('p');
body.appendChild(p);
}
</script>
You have to remove the previous table first. Currently the code that you have keeps appending new table to the body only but all the previous elements still remain there.
To remove the previous table:
jQuery:
body.find("table").remove();
Javascript:
var tables = document.getElementsByTagName("table");
for (var i = 0; i < tables.length; i++) {
tables[i].remove();
}
You can insert the code above before the line body.appendChild(tbl)
Note: jQuery function remove() will not throw error even if the table does not exist at the time of executing the code.
function tableCreate(maxyear, s4italka, a, b, c, d, e, f, g, h, i, j, k, l) {
var imena = ["Выручка", "Управляющая кампания", "Профилактика", "Налог на Недвижимость", "Страховка", "Амортизация", "Тело кредита", "%-ные выплаты банку", "%-ные выплаты себе", "Доход",
"Налог (15%)", "Финансовый результат"];
var dannie = [a, b, c, d, e, f, g, h, i, j, k, l];
$('.myTabel').remove();
var body = document.getElementsByTagName('body')[0];
var tbl = document.createElement('table');
$(tbl).addClass('myTabel');
tbl.style.width = '40%';
tbl.setAttribute('border', '1');
var tbdy = document.createElement('tbody');
var trh = document.createElement('tr');
var th = document.createElement('th');
var m = s4italka + 2015;
th.appendChild(document.createTextNode('Результат на ' + m + ' год'))
th.setAttribute('colSpan', '2');
trh.appendChild(th)
tbdy.appendChild(trh);
for (var i = 0; i < 12; i++) {
var tr = document.createElement('tr');
for (var j = 0; j < 2; j++) {
var td = document.createElement('td');
if ((j % 2) != 0)
{ td.appendChild(document.createTextNode(dannie[i])) }
else {
td.appendChild(document.createTextNode(imena[i]))
}
tr.appendChild(td)
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
body.appendChild(tbl)
var p = document.createElement('p');
body.appendChild(p);
}
I am loading data from a json object into a table on my page. Then I allow the user to filter that data via an input and display only the matches. My method of doing this is surely not great but it does work.
Now I want to do the exact same thing with a list of airports and their codes. Problem is that the airport list is much longer and the page bogs down significantly when loading the table with data and when it searches for the user's input in the table.
Here's the information for the page that does work so you can se what Im doing.
What can I do differently to achive the same effect I have here when I have a much larger data set to search?
Page Displaying data: (type "american airlines" or "aa"as an example)
https://pnrbuilder.com/_popups/dataDecoder.php
json object containing airline information:
https://pnrbuilder.com/_java/airlineDecoder.js
Sript that loads data to the page and filters it based on user input:
https://pnrbuilder.com/_java/decodeData.js
Here's the most significant parts of my code:
// This function is called by a for loop on dom ready
// It basically prints data stored in a json object to a table on the page
function fillInfo(line) {
var table = document.getElementById('decodeTable');
var row = document.createElement('tr');
table.appendChild(row);
var col1 = document.createElement('td');
row.appendChild(col1);
var curCode = document.createTextNode(arlnInfo.d[line].IATA);
col1.appendChild(curCode);
var col2 = document.createElement('td');
row.appendChild(col2);
var curArln = document.createTextNode(arlnInfo.d[line].Airline);
col2.appendChild(curArln);
var col3 = document.createElement('td');
row.appendChild(col3);
var curPre = document.createTextNode(arlnInfo.d[line].Prefix);
col3.appendChild(curPre);
var col4 = document.createElement('td');
row.appendChild(col4);
var curIcao = document.createTextNode(arlnInfo.d[line].ICAO);
col4.appendChild(curIcao);
var col5 = document.createElement('td');
row.appendChild(col5);
var curCnty = document.createTextNode(arlnInfo.d[line].Country);
col5.appendChild(curCnty);
}
// This function checks user input against data in the table
// If a match is found whitin a row, the row containing the match is shown
// If a match is not found that row is hidden
function filterTable(input) {
var decodeTable = document.getElementById('decodeTable');
var inputLength = input.length;
// THis first part makes sure that all rows of the generated table are hidden when no input is present
if (inputLength == 0) {
for (var r = 1; r < decodeTable.rows.length; r++) {
decodeTable.rows[r].style.display = "none";
}
}
// This part checks just the airline codes "column" of the table when input is only one or two characters
else if (inputLength < 3) {
for (var r = 1; r < decodeTable.rows.length; r++) {
var celVal = $(decodeTable.rows[r].cells[0])
.text()
.slice(0, inputLength)
.toLowerCase();
if (celVal == input) {
decodeTable.rows[r].style.display = "";
} else {
decodeTable.rows[r].style.display = "none";
}
}
}
// This part checks several "columns" of the table when input is more than two characters
else if (inputLength > 2) {
for (var r = 1; r < decodeTable.rows.length; r++) {
var celVal = $(decodeTable.rows[r].cells[2])
.text()
.slice(0, inputLength)
.toLowerCase();
var celVal2 = $(decodeTable.rows[r].cells[1])
.text();
if (celVal == input || celVal2 == input) {
decodeTable.rows[r].style.display = "";
} else if (celVal2.replace(/<[^>]+>/g, "")
.toLowerCase()
.indexOf(input) >= 0) {
decodeTable.rows[r].style.display = "";
} else {
decodeTable.rows[r].style.display = "none";
}
}
}
}
The first little optimization you could apply is not to do the entire filter on every key up, wait until the user finished typing so delay calling it for half a second:
var timeOut = 0;
$("#deCode").keyup(function () {
// cancel looking, the user typed another character
clearTimeout(timeOut);
// set a timeout, when user doesn't type another key
// within half a second the filter will run
var input = $("#deCode").val().toLowerCase().trim();
timeOut=setTimeout(function(){
filterTable(input)
},500);
});
The next is comparing to your json data instead of jquery objects and converting your JSON data to lower case after creating the table so you don't have to check toLowerCase every time for every row:
function filterTable(input) {
var decodeTable = document.getElementById('decodeTable');
var inputLength = input.length;
if (inputLength ==0) {
for (var r = 1; r < decodeTable.rows.length; r++) {
decodeTable.rows[r].style.display = "none";
}
}
else if (inputLength <3) {
for (var r = 0; r < arlnInfo.d.length; r++) {
if (arlnInfo.d[r].IATA.indexOf(input)===0) {
decodeTable.rows[r+1].style.display = "";
}
else {
decodeTable.rows[r+1].style.display = "none";
}
}
}
else if (inputLength > 2) {
for (var r = 0; r < arlnInfo.d.length; r++) {
if (arlnInfo.d[r].Prefix.indexOf(input)===0) {
decodeTable.rows[r].style.display = "";
}
else if (arlnInfo.d[r].Airline.indexOf(input) >= 0) {
decodeTable.rows[r + 1].style.display = "";
}
else {
decodeTable.rows[r + 1].style.display = "none";
}
}
}
}
Problem is with your JSON data: "Prefix": 430 causes arlnInfo.d[r].Prefix.slice(0, inputLength) to throw an error because the data isn't a string but a number. If you have control over the JSON then you should convert these values to string ("Prefix":"430"), If you don't then convert it once and re create airlineDecoder.js using JSON.stringify(arlnInfo);
To convert your JSON you can copy and paste this in the chrome console (press F12) and run it (press enter). It'll log the converted JSON but you may need an IDE like netbeans to re format it:
var i = 0;
for(i=0;i<arlnInfo.d.length;i++){
arlnInfo.d[i].Prefix=arlnInfo.d[i].Prefix+"";
}
console.log("var arlnInfo = " + JSON.stringify(arlnInfo));
A last optimization you can apply is use DocumentFragment instead of directly adding every row to DOM, here we convert the JSON data to lower case so we don't have to do that for every search:
var decodeTable = document.getElementById('decodeTable');
function createTable() {
var df = document.createDocumentFragment();
for (var i = 0; i < arlnInfo.d.length; i++) {
fillInfo(i, df);
arlnInfo.d[i].IATA = arlnInfo.d[i].IATA.toLowerCase()
arlnInfo.d[i].Prefix = arlnInfo.d[i].Prefix.toLowerCase();
arlnInfo.d[i].Airline = arlnInfo.d[i].Airline.toLowerCase();
}
decodeTable.appendChild(df);
}
createTable();
....
function fillInfo(line,df) {
var row = document.createElement('tr');
df.appendChild(row);
....
row.style.display = "none";
}
I am trying to create mine field game. "I am very new to Js".
What I have done so far:
var level = prompt("Choose Level: easy, medium, hard");
if (level === "easy") {
level = 3;
} else if (level === "medium") {
level = 6;
} else if (level === "hard") {
level = 9;
}
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
var tblBody = document.createElement("tbody");
for (var i = 1; i <= 10; i++) {
var row = document.createElement("tr");
document.write("<br/>");
for (var x = 1; x <= 10; x++) {
var j = Math.floor(Math.random() * 12 + 1);
if (j < level) {
j = "mined";
} else {
j = "clear";
}
var cell = document.createElement("td");
var cellText = document.createTextNode(j + " ");
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "2");
So I create here 2d table and enter 2 random values in rows and columns (mined or clear).
Where I am stuck is:
Check if td = mined it dies otherwise open the box(td) etc.
How do I assign value of td? I mean how can I check which value(mined/clear) there is in the td which is clicked?
Ps: Please don't write the whole code:) just show me the track please:)
Thnx for the answers!
Ok! I came this far.. But if I click on row it gives sometimes clear even if I click on mined row or vice versa!
// create the table
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
tbl.setAttribute('id','myTable');
var tblBody = document.createElement("tbody");
//Create 2d table with mined/clear
for(var i=1;i<=10;i++)
{
var row = document.createElement("tr");
document.write("<br/>" );
for(var x=1;x<=10;x++)
{
var j=Math.floor(Math.random()*12+1);
if(j<level)
{
j = "mined";
}
else{
j = "clear";
}
var cell = document.createElement("td");
var cellText = document.createTextNode(j + "");
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "2");
//Check which row is clicked
window.onload = addRowHandlers;
function addRowHandlers() {
var table = document.getElementById("myTable");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row)
{
return function() {
var cell = row.getElementsByTagName("td")[0];
var id = cell.innerHTML;
if(id === "mined")
{
alert("You died");
}else
{
alert("clear");
}
};
}
currentRow.onclick = createClickHandler(currentRow);
}
}
I think I do something wrong with giving the table id "myTable"..
Can you see it?
Thank you in advance!
So, the idea would be:
assign a click event to each td cell:
td.addEventListener('click', mycallback, false);
in the event handler (callback), check the content of the td:
function mycallback(e) { /*e.target is the td; check td.innerText;*/ }
Pedagogic resources:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td?redirectlocale=en-US&redirectslug=HTML%2FElement%2Ftd
https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener
JavaScript, getting value of a td with id name