I had this block of code in javascript which does add dynamic input fields. Every thing works fine at this point. My question is how would I add more input fields within the table in other cell respectively with the village name input fields? When user Add Village 1/Remove Village 1, either of the action should add/remove aligning input field on column named:Type of participatory forest management, Year participatory management process started and Size of forest. The input fields increment of the columns mentioned above should reflect the increment of dynamic input field of village name column. Later I will use the dynamic input fields with Php on sending the values to database. Thanks for your time!
Below is script:
script code:
<script language="JavaScript" type="text/javascript">
function getById(e){return document.getElementById(e);}
function newElement(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}
function addForestName()
{
var tbl = getById('tblSample'); //note the single line generic functions written above
var lastRow = tbl.rows.length;
// if there's no header row in the table, then iteration = lastRow + 1
var iteration = lastRow;
var row = tbl.insertRow(lastRow);
// Column which has iteration count
var cell_no = row.insertCell(0);
var textNode = newTxt(iteration);
cell_no.appendChild(textNode);
// Column which has the forest name
var frstNameCell = row.insertCell(1);
var el_input = newElement('input'); //create forest name input
el_input.type = 'text';
el_input.name = 'forest_text_' + iteration;
el_input.id = 'forest_text_' + iteration;
el_input.size = 40;
frstNameCell.appendChild(el_input);
// Column which has the village name
var villageNameCell = row.insertCell(2);
var el_label = newElement('label');
el_label.for = 'village_text_' + iteration + '_1';
var el_labelValue = '1.';
textNode = newTxt(el_labelValue);
el_label.appendChild(textNode);
villageNameCell.appendChild(el_label);
el_input = newElement('input');
el_input.type = 'text';
el_input.name = 'village_text_' + iteration + '_1';
el_input.id = 'village_text_' + iteration + '_1';
el_input.size = 40;
villageNameCell.appendChild(el_input);
el_btn = newElement('input'); //create village name add button
el_btn.type = 'button';
el_btn.name = 'village_btn_' + iteration;
el_btn.id = 'village_btn_' + iteration;
el_btn.value = 'Add Village Forest ' + iteration;
el_btn.addEventListener('click',addMoreVillageNames, false);
villageNameCell.appendChild(el_btn);
el_btn = newElement('input'); //create village name remove button
el_btn.type = 'button';
el_btn.name = 'village_rembtn_' + iteration;
el_btn.id = 'village_rembtn_' + iteration;
el_btn.value = 'Remove Village Forest ' + iteration;
el_btn.addEventListener('click',removeVillageName, false);
villageNameCell.appendChild(el_btn);
var frstManagCell = row.insertCell(3); // create forest management input
el_input = newElement('input');
el_input.type = 'text';
el_input.name = 'frstManage_text_' + iteration + '_1';
el_input.id = 'frstManage_text_' + iteration + '_1';
el_input.size = 40;
frstManagCell.appendChild(el_input);
var yerPartCell = row.insertCell(4); // create year participatory input
el_input = newElement('input');
el_input.type = 'text';
el_input.name = 'yrPart_text_' + iteration + '_1';
el_input.id = 'yrPart_text_' + iteration + '_1';
el_input.size = 40;
yerPartCell.appendChild(el_input);
var frstSizeCell = row.insertCell(5); // create forest size input
el_input = newElement('input');
el_input.type = 'text';
el_input.name = 'frstSize_text_' + iteration + '_1';
el_input.id = 'frstSize_text_' + iteration + '_1';
el_input.size = 40;
frstSizeCell.appendChild(el_input);
}
function addMoreVillageNames(){
rowNumber = (this.id).substring((this.id.length)-1, this.id.length); //to get Row Number where one more input needs to be added.
var childElCount;
var parentCell = this.parentNode;
var inputCount = parentCell.getElementsByTagName('label').length; //to get the count of input fields present already
var newFieldNo = inputCount + 1; //input current count by 1 to dynamically set next number for the new field
//temporarily remove the add and remove buttons to insert the new field before it.we are doing this loop only twice because we know the last 2 input elements are always the two buttons
for (var i=0; i<2; i++){
childElCount = parentCell.getElementsByTagName('input').length; //get count of child input elements (including text boxes);
parentCell.removeChild(parentCell.getElementsByTagName('input')[childElCount-1]);
}
var lineBreak = newElement('br');
parentCell.appendChild(lineBreak); //add a line break after the first field
var el_label = newElement('label');
el_label.for = 'village_text_' + rowNumber + '_' + newFieldNo;
var el_labelValue = newFieldNo + '.';
var textNode = newTxt(el_labelValue);
el_label.appendChild(textNode);
parentCell.appendChild(el_label); //create and add label
var el_input = newElement('input');
el_input.type = 'text';
el_input.name = 'village_text_' + rowNumber + '_' + newFieldNo;
el_input.id = 'village_text_' + rowNumber + '_' + newFieldNo;
el_input.size = 40;
parentCell.appendChild(el_input); //create and add input field
var el_btn = newElement('input'); //add the village name add button again
el_btn.type = 'button';
el_btn.name = 'village_btn_' + rowNumber;
el_btn.id = 'village_btn_' + rowNumber;
el_btn.value = 'Add Village ' + rowNumber;
el_btn.addEventListener('click',addMoreVillageNames, false);
parentCell.appendChild(el_btn);
el_btn = newElement('input'); //create village name remove button
el_btn.type = 'button';
el_btn.name = 'village_rembtn_' + rowNumber;
el_btn.id = 'village_rembtn_' + rowNumber;
el_btn.value = 'Remove Village ' + rowNumber;
el_btn.addEventListener('click',removeVillageName, false);
parentCell.appendChild(el_btn);
}
function removeForestName()
{
var tbl = document.getElementById('tblSample');
var lastRow = tbl.rows.length;
if (lastRow > 2) tbl.deleteRow(lastRow - 1);
}
function removeVillageName()
{
var rowNumber = (this.id).substring((this.id.length)-1, this.id.length); //to get Row Number where one more input needs to be added.
var parentCell = this.parentNode;
var lblCount = parentCell.getElementsByTagName('label').length;
var inputCount = parentCell.getElementsByTagName('input').length;
var brCount = parentCell.getElementsByTagName('br').length;
//Remove will not happen if there is only one label-input combo left.
if(lblCount>1)
parentCell.removeChild(parentCell.getElementsByTagName('label')[lblCount-1]);
if(inputCount>3)
parentCell.removeChild(parentCell.getElementsByTagName('input')[inputCount-3]); //Delete the third last element because the last two are always the two buttons.
parentCell.removeChild(parentCell.getElementsByTagName('br')[brCount-1]);
}
window.onload = addForestName;
</script>
<form action="tableaddrow_nw.html" method="get">
<table width="640" border="1" id="tblSample">
<tr>
<td>No.</td>
<td>Forest Name</td>
<td width="40">Name of the villages <br />participating in managing</td>
<td>Type of participatory forest management</td>
<td>Year participatory management process started</td>
<td>Size of forest</td>
</tr>
</table>
</form>
<p>
<input type="button" value="Add" onclick="addForestName();" />
<input type="button" value="Remove" onclick="removeForestName();" />
</p>
If I understood your question correctly, the below is what you are looking for. Using the following method you can get hold of the required table column (Column Number is hard coded because this is just a sample). Once you have got hold of the required column, adding/removing fields should be straight-forward. Check out this Fiddle for a working sample.
var tbl = document.getElementById('tblSample');
var frstMgmtCell = tbl.rows[rowNumber].cells[3]; //Get hold of the Forest Mgmt Column of that specific row.
On a side note, there are a lot of repeated items which you might want to convert into separate functions for better maintainability.
Related
I have an HTML page with 3 tables on it. I want to be able to copy specific cells in a table row to the clipboard. The row could come from any of the 3 tables.
Using the code below, I highlight and copy the row for a table with an ID of "final". How do I make this work for any of the 3 tables? I tried by getElementsByTagName and labeling them the same name but did not work - understandably so. Is there a way to designate the selected table? I am trying to avoid copying the whole row and might eventually add the formatted msg to a new page rather than copy to the clipboard.
function copy_highlight_row() {
var table = document.getElementById('final');
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function () {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
rowsNotSelected[row].style.backgroundColor = "";
rowsNotSelected[row].classList.remove('selected');
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
rowSelected.style.backgroundColor = "yellow";
rowSelected.className += " selected";
var cellId = this.cellIndex + 1
msg = 'Title: ' + rowSelected.cells[0].innerHTML;
msg += '\r\nDescription: ' + rowSelected.cells[1].innerHTML;
msg += '\n\nLink: ' + rowSelected.cells[2].innerHTML;
msg += '\nPublication Date: ' + rowSelected.cells[3].innerHTML;
//msg += '\nThe cell value is: ' + this.innerHTML copies cell selected
navigator.clipboard.writeText(msg);
}
}
};
Based on a couple of the suggestions I came up with the following:
function highlight_row() {
var cells = document.querySelectorAll('td')
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function () {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var t_ID = this.closest('table').id
var table=document.getElementById(t_ID);
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
rowsNotSelected[row].style.backgroundColor = "";
rowsNotSelected[row].classList.remove('selected');
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
rowSelected.style.backgroundColor = "yellow";
rowSelected.className += " selected";
var cellId = this.cellIndex + 1
msg = 'Title: ' + rowSelected.cells[0].innerHTML;
msg += '\r\nDescription: ' + rowSelected.cells[1].innerHTML;
msg += '\n\nLink: ' + rowSelected.cells[2].innerHTML;
msg += '\nPublication Date: ' + rowSelected.cells[3].innerHTML;
navigator.clipboard.writeText(msg);
}
}
}
At the end of the html I call the function. The HTML contains 3 tables and this enabled me to click on any table, highlight the row, and copy the correct range of cells.
I'm new to Google Apps Script so I'm looking for some advice. There's multiple parts and I managed to do some of it but I'm stuck on others. Any help would be much appreciated.
I'm trying to make a script that:
drafts a reply to emails that contain specific keywords (found in the body or the subject line).
I also want it to include a template with data inputted from a Google Sheets file.
It would be preferable if the draft can be updated without making a duplicate whenever the Sheet is modified.
I plan on also including a row of values (the first one) that correspond to the Subject columns in the second row the but I haven't gotten to it yet.
Some details about the Google Sheet:
Each row corresponds to a different person and email address that regularly emails me.
The first three columns are details about the person which I include in the body of my draft.
Each column after that represents a different string or keyword I expect to find in the subject of the emails sent to me.
The rows underneath contain two patterned code-words separated by a space in one cell that I want to be able to choose from. Such as:
3 letters that can contain permutations of the letters m, g, r (for ex: mmg, rgm, rgg, gmg)
and 0-3 letters with just p's (for ex: p, pp, ppp, or blank)
I want to be able to detect the different codes and assign it to a variable I can input into my draft.
What I have so far:
I'm able to draft replies for emails within my specified filter. However, I only have it set up to reply to the person's most recent message. I want to be able for sort through the filter for specific emails that contain a keyword in the subject line when it loops through the columns.
I'm able to input static strings from the Sheet into the body of my email but I'm still having trouble with the patterned codewords.
I was able to loop through more than one row in earlier version but now it's not. I'll look over it again later.
Here's my code:
function draftEmail() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 1; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 2; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var grader = row[0]; // Col A: Grader's name
var firstName = row[1]; // Col B: Student's first name
var studentEmail = row[2]; // Col C: Student's email
var grade = row[3].split(' '); // Col D: Grade
var pgrade = grade[1];
var hgrade = grade[0];
for (var n = 1; n < data.length; ++n) {
var srow = data[n];
var subjectCol = srow[3];
var threads = GmailApp.getUserLabelByName('testLabel').getThreads();
for (i=0; i < threads.length; i++)
{
var thread = threads[i];
var messages = thread.getMessages(); // get all messages in thread i
var lastmsg = messages.length - 1; // get last message in thread i
var emailTo = WebSafe(messages[lastmsg].getTo()); // get only email id from To field of last message
var emailFrom = WebSafe(messages[lastmsg].getFrom()); // get only email id from FROM field of last message
var emailCC = WebSafe(messages[lastmsg].getCc()); // get only email id from CC field of last message
// form a new CC header for draft email
if (emailTo == "")
{
var emailCcHdr = emailCC.toString();
} else
{
if (emailCC == "")
{
var emailCcHdr = emailTo.toString();
} else
{
var emailCcHdr = emailTo.toString() + "," + emailCC.toString();
}
}
var subject = messages[lastmsg].getSubject().replace(/([\[\(] *)?(RE|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$/igm,"");
// the above line remove REs and FWDs etc from subject line
var emailmsg = messages[lastmsg].getBody(); // get html content of last message
var emaildate = messages[lastmsg].getDate(); // get DATE field of last message
var attachments = messages[lastmsg].getAttachments(); // get all attachments of last message
var edate = Utilities.formatDate(emaildate, "IST", "EEE, MMM d, yyyy"); // get date component from emaildate
var etime = Utilities.formatDate(emaildate, "IST", "h:mm a"); // get time component from emaildate
if (emailFrom.length == 0)
{
// if emailFrom is empty, it probably means that you may have written the last message in the thread. Hence 'you'.
var emailheader = '<html><body>' +
'On' + ' ' +
edate + ' ' +
'at' + ' ' +
etime + ',' + ' ' + 'you' + ' ' + 'wrote:' + '</body></html>';
} else
{
var emailheader = '<html><body>' +
'On' + ' ' +
edate + ' ' +
'at' + ' ' +
etime + ',' + ' ' + emailFrom + ' ' + 'wrote:' + '</body></html>';
}
var emailsig = '<html>' +
'<div>your email signature,</div>' +
'</html>'; // your email signature i.e. common for all emails.
// Build the email message
var emailBody = '<p>Hi ' + firstName + ',<p>';
emailBody += '<p>For ' + subjectCol + ', you will be graded on #1, 2, and 3: <p>';
emailBody += '<p>Participation: ' + pgrade + '</p>';
emailBody += '<p>HW grade: ' + hgrade + '</p>';
emailBody += '<p>If you have any questions, you can email me at ' + grader + '#email.com.<p>';
emailBody += '<p>- ' + grader;
var draftmsg = emailBody + '<br>' + emailsig + '<br>' + emailheader + '<br>' + emailmsg + '\n'; // message content of draft
// Create the email draft
messages[lastmsg].createDraftReply(
" ", // Body (plain text)
{
htmlBody: emailBody // Options: Body (HTML)
}
);
}
}
}
function WebSafe(fullstring)
{
var splitString = fullstring.split(",");
var finalarray = [];
for (u=0; u < splitString.length; u++)
{
var start_pos = splitString[u].indexOf("<") + 1;
var end_pos = splitString[u].indexOf(">",start_pos);
if (!(splitString[u].indexOf("<") === -1 && splitString[u].indexOf(">",start_pos) === -1)) // if < and > do exist in string
{
finalarray.push(splitString[u].substring(start_pos, end_pos));
} else if (!(splitString[u].indexOf("#") === -1))
{
finalarray.push(splitString[u]);
}
}
var index = finalarray.indexOf(grader + "#email.com"); // use your email id. if the array contains your email id, it is removed.
if (index > -1) {finalarray.splice(index, 1);}
return finalarray
}
}
I've never coded in JavaScript before or used Google Scripts so I mostly looked at similar examples.
Thank you for any feedback.
I prefer reading code that isn't too nested. So I took the liberty to re-write your code and make it easier to read.
Your main function:
function mainFunction(){
// Use data from the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var threads = GmailApp.getUserLabelByName('<YOUR-LABEL-HERE>').getThreads();
var subject1 = data[1][3];
// Work through each row in the spreadsheet omit headers
for (var i = 2; i < data.length; ++i) {
// Get grader's data
var grader = getGrader(data[i]);
console.log(grader);
// Loop through threads
for (j=0; j < threads.length; j++){
var thread = threads[j];
// Get last message in thread
var messages = thread.getMessages();
var lastMsg = messages[messages.length - 1];
var email = new Email(grader, lastMsg, subject1);
// Create the draft reply.
var draftMessageBody = createDraftMessage(email);
lastMsg.createDraftReply(draftMessageBody);
}
}
}
Support functions:
Function getGrader:
function getGrader(array){
var row = array
var grader = {}
grader.grader = row[0];
grader.firstName = row[1];
grader.studentEmail = row[2];
var grade = row[3].split(' ');
grader.pgrade = grade[1];
grader.hgrade = grade[0];
return grader
}
Function webSafe:
function webSafe(fullstring, grader){
var splitString = fullstring.split(",");
var finalarray = [];
for (u=0; u < splitString.length; u++){
var start_pos = splitString[u].indexOf("<") + 1;
var end_pos = splitString[u].indexOf(">",start_pos);
// if < and > do exist in string
if (!(splitString[u].indexOf("<") === -1 && splitString[u].indexOf(">",start_pos) === -1)){
finalarray.push(splitString[u].substring(start_pos, end_pos));
} else if (!(splitString[u].indexOf("#") === -1)){
finalarray.push(splitString[u]);
}
}
// use your email id. if the array contains your email id, it is removed.
var index = finalarray.indexOf(grader.grader + "#mangoroot.com");
if (index > -1) {
finalarray.splice(index, 1);
}
return finalarray
}
Function Email: Behaves like a class
var Email = function(grader, lastMsg, subject){
this.signature = "your_email_signature,";
this.grader = grader;
this.to = webSafe(lastMsg.getTo(), this.grader);
this.from = webSafe(lastMsg.getFrom(), this.grader);
this.cc = webSafe(lastMsg.getCc(), this.grader);
this.subject = lastMsg.getSubject().replace(/([\[\(] *)?(RE|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$/igm,"");
this.message = lastMsg.getBody();
this.date = lastMsg.getDate();
this.attachments = lastMsg.getAttachments();
this.subject1 = subject;
this.ccHeader = function() {
var ccHeader = "";
if (this.to == "" || this.cc == ""){
ccHeader = this.cc.toString();
}
else {
ccHeader = this.to.toString() + "," + this.cc.toString();
}
return ccHeader
}
this.eDate = function() {
return Utilities.formatDate(this.date, "IST", "EEE, MMM d, yyyy");
}
this.eTime = function() {
return Utilities.formatDate(this.date, "IST", "h:mm a");
}
this.header = function() {
var header = ''.concat('On ');
if (this.from.length == 0){
header += this.eDate().concat(' at ',this.eTime(),', you wrote: ');
}
else {
header += this.eDate().concat(' at ',this.eTime(),', ',this.from,' wrote: ');
}
return header
}
this.body = function(){
var grader = this.grader;
var body = '<div>'.concat('<p>Hi ',grader.firstName,',</p>');
body += '<p>For '.concat(this.subject1,', you will be graded on #1, 2, and 3: </p>');
body += '<p>Participation: '.concat(grader.pgrade,'</p>');
body += '<p>HW grade: '.concat(grader.hgrade,'</p>');
body += '<p>If you have any questions, you can email me at '.concat(grader.grader,'#mangoroot.com.</p>');
body += '<p>- '.concat(grader.grader,'</p>','</div>');
return body;
}
}
Function createDraftMessage:
function createDraftMessage(email){
var draft = '<html><body>'.concat(email.body);
draft += '<br>'.concat(email.signature);
draft += '<br>'.concat(email.header);
draft += '<br>'.concat(email.message);
draft += '<br>'.concat('</body></html>');
return draft;
}
Now when you run mainFunction() you should get your expected drafts.
Notes:
It is good practice to keep functions flat, flat is better than nested. Makes the code more readable and maintainable.
Also be consistent in your variable naming style.
var emailMsg = ''; // Good.
var emailmsg = ''; // Hard to read.
Have a read about classes
I am creating a form using javascript ,and subsequently adding the elements.
This code runs onclick event of a button .
But the generated code contains the <form> and </form> code in single line and the elements generated after this line.
I have given inline style border to the form.
The form border covers only one line and the controls are generated outside the form.
How to bring all elements between the <form> and </form> ?
A portion of my code below.
var f_id = frm_main_id + "_set" + (set_no + 1);
var criterias_csv_id = frm_main_id + '_criteria_csv';
var criterias_csv = document.getElementById(criterias_csv_id).value
var criteria_array = criterias_csv.split("|");
var fldno = 0;
var i;
var fid = "activity" + act_no + "_time_" + (set_no + 1) + "time";
var x = document.getElementById("id_" + act_no + "_fieldset")
var f = document.createElement("form");
f.setAttribute('method', "post");
f.setAttribute('id', f_id);
f.setAttribute('action', "submit_criteria.php");
f.style.borderStyle = "solid";
x.appendChild(f);
//var table = document.getElementById("id_" + act_no + "_table");
var new_table = document.createElement("TABLE");
new_table.setAttribute('class', "class_open");
new_table.setAttribute('form', f_id);
new_table.style.borderStyle = "solid";
x.appendChild(new_table);
var new_row = document.createElement("TR");
new_table.appendChild(new_row);
var th = document.createElement("th");
new_row.appendChild(th);
th.innerHTML = "Observed Time" + (set_no + 1);
var th = document.createElement("th");
new_row.appendChild(th);
var s = document.createElement("input");
s.setAttribute('type', "datetime-local");
s.setAttribute('id', fid);
s.setAttribute('form', f_id);
s.setAttribute('required', true);
th.appendChild(s);
for (i = 0; i < criteria_array.length; i += 2) {
fldno++;
fid = "activity" + act_no + "_time_" + (set_no + 1) + "_criteria_" + fldno;
var new_row = document.createElement("TR");
new_table.appendChild(new_row);
if (i == 0) {}
var field_type = "";
var fldname = criteria_array[i];
field_type = criteria_array[i + 1];
field_type = field_type.trim();
switch (field_type) {
case "Numeric":
field_type = "number";
break;
case "TEXT":
field_type = "text";
break;
}
var new_row = document.createElement("TR");
new_table.appendChild(new_row);
new_col = document.createElement("td");
new_row.appendChild(new_col);
new_col1 = document.createElement("td");
new_row.appendChild(new_col1);
new_label = document.createElement("label");
new_label.setAttribute("for", fid);
new_label.innerHTML = fldno + ")" + fldname;
new_col.appendChild(new_label);
switch (field_type) {
case "number":
case "text":
var s = document.createElement("input");
s.setAttribute('type', field_type);
s.setAttribute('id', fid);
s.setAttribute('required', true);
s.setAttribute('form', f_id);
new_col1.appendChild(s);
break;
case "YN":
var s = document.createElement("SELECT");
s.setAttribute('id', fid);
s.setAttribute('form', f_id);
var option = document.createElement("option");
option.text = "";
option.value = "";
s.add(option);
var option = document.createElement("option");
option.text = "No";
option.value = "N";
s.add(option);
var option = document.createElement("option");
option.text = "Yes";
option.value = "Y";
s.add(option);
new_col1.appendChild(s);
break;
default:
break;
}
}
new_row = document.createElement("TR");
new_table.appendChild(new_row);
new_col = document.createElement("td");
new_row.appendChild(new_col);
s = document.createElement("input"); //input element, Submit button
s.setAttribute('type', "submit");
s.setAttribute('value', "Save");
s.setAttribute('form', f_id);
s.setAttribute('onclick', "x()");
//"clk_save(', $act_no, ',', $edit, ')">
new_col.append(s);
new_col = document.createElement("td");
new_row.appendChild(new_col);
new_col.append(s);
}
I currently set the form attribute of each element separately and it works fine. But the border around the form is only for the first line.
Any idea??
Thanks for suggestions.
I have posted the full code.
I did following correction and everything is fine
x.appendChild(new_table); replaced x. with f.
Based on the button click event, I want to add rows dynamically at the bottom of an existing table.
I had done the same using Javascript which is given below. It is working fine in Chrome browser whereas in IE the rows are getting added at the top rather than at the bottom.
If I click the button multiple times then could see that all the rows are getting added at the top one after the other in IE.
function addRow(tableID) {
var table = document.getElementById(tableID);
var tbody = table.getElementsByTagName('tbody')[0];
var rowCount = table.querySelectorAll("tbody tr").length;
var row = tbody.insertRow(-1);
var cell1 = row.insertCell(0);
cell1.classList.add("PadLeft10");
cell1.classList.add("PadBottom5");
cell1.classList.add("textcenter");
cell1.width = "2%";
var element1 = document.createElement("input");
element1.type = "checkbox";
element1.name = "element1[" + index + "].selected";
element1.id = "element1[" + index + "].selected";
cell1.appendChild(element1);
[...]
}
I could see in the docs that tbody.insertRow(-1) should append row at the last in both IE and Chrome, but for me in IE it is getting added at the top. I tried many ways but in all it works fine in Chrome but not in IE.
Any help?
If the insertRow part is the problem, you can do this to reliably add to the end instead:
var row = document.createElement("tr");
tbody.appendChild(row);
Similarly, var cell1 = row.insertCell(0); (if it is also a problem) can be:
var cell1 = document.createElement("tr");
row.insertBefore(cell1, row.firstChild);
Finally, MDN says that IE has long supported insertAdjacentHTML (all the way back to IE4), so that entire method could be replaced with the following if you like:
function addRow(tableID) {
var table = document.getElementById(tableID);
var tbody = table.querySelector("tbody");
var rowCount = table.querySelectorAll("tr").length; // Or: `= table.rows.length;`
// ***Where does `index` come from? Did you mean `rowCount`?
var name = "element1[" + index + "].selected";
var html =
'<tr>' +
'<td class="PadLeft10 PadBottom5 textcenter" width="2%">' +
'<input type="checkbox" name="' + name + '" id="' + name + '">' +
'</td>' +
'</tr>';
tbody.insertAdjacentHTML("beforeend", html);
// ...
}
Problem:
I have a dynamically created HTML table, that is used for filling out time sheets. It is created programmatically - there is no formal control. The design is a mix of CSS with text boxes being created through JavaScript. Now each 'row' of this table is in a class called 'divRow', and is separated from the others by having 'r' and the number of the row assigned to it as the class (i.e 'divRow r1', 'divRow r2', etc.).
Within each of these 'divRow's, I have cells in a class called 'divCell cc'. These do not have any identifiers in the class name. At the very last cell, I have a 'Total' column, which ideally calculates the total of the row and then adds it into a dynamically created text box.
What I have at the moment:
// Function to create textboxes on each of the table cells.
$(document).on("click", ".cc", function(){
var c = this;
if(($(c).children().length) === 0) {
var cellval = "";
if ($(c).text()) {
cellval = $(this).text();
if(cellval.length === 0) {
cellval = $(this).find('.tbltxt').val();
}
}
var twidth = $(c).width() + 21;
var tid= 't' + c.id;
if(tid.indexOf('x17') >= 0){
var thtml = "<input id='t" + c.id + "' type='text' Class='tbltxt' style='width: " + twidth + "px;' readonly />";
eval(spproc(spcol(t[getx(c.id)],thtml,tid,twidth)));
//var getRow = $(this).parent().attr('class'); - this gets the 'divRow r#' that it is currently on.
var arr = document.getElementsByClassName('cc');
var tot = 0;
for(var i = 0; i<arr.length; i++){
if(parseInt(arr[i].innerHTML) > 0){
tot += parseInt(arr[i].innerHTML);}
}
$('#t' + c.id).focus();
$(this).children().val(tot);
}else{
var thtml = "<input id='t" + c.id + "' type='text' Class='tbltxt' style='width: " + twidth + "px;' />";
eval(spproc(spcol(t[getx(c.id)],thtml,tid,twidth)));
$('#t' + c.id).focus();
$('#t' + c.id).val(cellval);
}}
});
As you can see, when the user clicks on the 'divCell cc', it creates a text box if one is not present. If the user clicks on the 17th column ('x17'), then it runs the for loop, and assigns the value of the total to the text box.
What I need to happen:
So what happens now is that the last cell sums the total of each cell that has a value. However, they are not row-dependent. I need it to calculate based on the row that it is currently 'on'. So if I'm calculating the 2nd row, I don't want the sum of the first, second and third being entered into the total, I just want the 2nd rows' values summed.
What I've tried:
I've tried looping through and using the 'divRow r#' number to try and get the items in the array that end in that number. (cells are given an id of 'x#y#' and the text boxes assigned to those cells are given an id of 'tx#y#').
I've tried getting elements by the cell class name, and then getting their parent class and sorting by that; didn't get far though, keep running into simple errors.
Let me know if you need more explanation.
Cheers,
Dee.
For anyone else that ever runs into this issue. I got it. I put the elements by the row class into an array, and then using that array, I got the childNodes from the row class. The reason the variable 'i' starts at 2 and not 0 is because I have 2 fields that are not counted in the TimeSheet table (Jobcode and description). It's working great now.
Cheers.
$(document).on("click", ".cc", function(){
var c = this;
if(($(c).children().length) === 0) {
var cellval = "";
if ($(c).text()) {
cellval = $(this).text();
if(cellval.length === 0) {
cellval = $(this).find('.tbltxt').val();
}
}
var twidth = $(c).width() + 21;
var tid= 't' + c.id;
if(tid.indexOf('x17') >= 0){
var thtml = "<input id='t" + c.id + "' type='text' Class='tbltxt' style='width: " + twidth + "px;' readonly />";
eval(spproc(spcol(t[getx(c.id)],thtml,tid,twidth)));
// Get current row that has focus
var getRow = $(this).parent().attr('class');
// Get the row number for passing through to the next statement
var rowPos = getRow.split('r', 5)[1];
// Get all the elements of the row class and assign them to the rowClass array
var rowClass = document.getElementsByClassName('r' + rowPos)
// Given the rowClass, get the children of the row class and assign them to the new array.
var arr = rowClass.item(0).childNodes
// Initialize the 'total' variable, and give it a value of 0
var tot = 0;
// Begin for loop, give 'i' the value of 2 so it starts from the 3rd index (avoid the Req Code and Description part of the table).
for(var i = 2; i<arr.length; i++){
if(parseInt(arr[i].innerHTML) > 0){
tot += parseInt(arr[i].innerHTML);}
}
// Assign focus to the 'Total' cell
$('#t' + c.id).focus();
// Assign the 'total' variable to the textbox that is dynamically created on the click.
$(this).children().val(tot);
}else{
var thtml = "<input id='t" + c.id + "' type='text' Class='tbltxt' style='width: " + twidth + "px;' />";
eval(spproc(spcol(t[getx(c.id)],thtml,tid,twidth)));
$('#t' + c.id).focus();
$('#t' + c.id).val(cellval);
}}
});