I had a table element in my Html file of FCK editor which i tried to replace with new table element using parentNode.replaceChild method.Though it works fine in Internet Explore 8 but gives me error in IE 6 as well as IE 7.The error i get is "property does not support this object or method".Here is my snippet of code:
var eSelected = FCK.Selection.MoveToAncestorNode( 'TABLE' );
var myTable = document.createElement('TABLE');
var temp1= '<span><strong>' + Title.value + '</strong></span>'; //title.value is value retrieved from a text box
var temp2= '<a onBlur="window.status=' + ';return true"
onMouseOver="window.status=' + ';return true" ' + 'onFocus="window.status=' + ';return true" onMouseOut="window.status=' + ';return true" ' +'href="javascript:pdfPopup('+'\'' + Name.value + '\''+');">'+Name.value+'</a><span>[' + Size.value + ']</span>'; //name.value is also retrieved from a text box
var row1 = myTable.insertRow(0); //create new rows in the table
var cell1= row1.insertCell(0);
cell1.innerHTML=temp1;
var row2 = myTable.insertRow(1);
var cell2= row2.insertCell(0);
cell2.innerHTML=temp2;
var row3 = myTable.insertRow(2);
var cell3= row3.insertCell(0);
cell3.innerHTML=' ';
eSelected.parentNode.replaceChild(myTable,eSelected); // I m getting error at this line`
Do you have a <tbody> tag enclosing the rows?
<table><tbody><tr></tr><tr></tr></tbody></table>
(Sorry, that I can't write this as a comment. I don't have the privileges to do so…)
Related
I'm a total novice at Javascript, but I was able to modify some scripts I found online to get a row emailed to the address in column B of that row. There are three places where I'm totally stuck:
How do I trigger the script to run when column B is updated?
In line two of my code, I've hard coded the row number as variable dataRow. How do I get the updated row from my spreadsheet?
The HTML is rendering in some instances, but not others. The td width in line 22 is not functioning, not is any of the html formatting in lines 46 and 47. I've tried a couple of techniques but nothing is working.
Thank you!
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRow = 232; //updated row in spreadhseet
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sh.getRange("E:T").getValues();
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;"'
var htmltable = ['<table ' + TABLEFORMAT +'>'];
row = 0;
htmltable += '<tr>';
for (col = 0 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + 'None' + '</td>';}
else
if (row === 0) {
htmltable += '<th>' + data[row][col] + '</th>';
}
else
if (col===10){htmltable += '<td>' + data[row][col] + '</td>';}
else
{htmltable += '<td width=400px" style="width:400px; background-color:yellow;">' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
row = dataRow - 1;
htmltable += '<tr>';
for (col = 0 ;col<16; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + 'None' + '</td>';}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
htmltable += '</table>';
var dataRange = sheet.getRange(dataRow, 1, 1, 19)
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[1];
var ccAddress = row[2];
var signature = '<span style="font-family:"Arial",sans-serif">Best</span></br>Adam Schwartz </span> </br><span style="font-size:10.0pt;font-family:"Arial",sans-serif;color:#48B8DD"> <stong> MANAGER OF ESCALATIONS - RESIDENTIAL</stong></span></br><span style="font-family:"Arial",sans-serif">SMS ASSIST</span><span style="font-size:9.0pt;font-family:"Arial",sans-serif;color:#6C6C6C"> 875 N. Michigan Ave. | Suite 2800 | Chicago, IL 60611 </span>';
var message = "Hello " + row[4] + "," + '</br></br>' +"One of your escalation model tasks was randomly selected for QA last week. Your scores are below, along with my notes." + '</br></br>' + htmltable + '</br></br>' + signature; // Assemble the body text
var subject = "Preventive Escalation Model QA " + row[19];
MailApp.sendEmail(emailAddress, subject, message, {htmlBody:message,cc:ccAddress});
}
}
First, you need an onEdit trigger in order to fire the function every time column B the spreadsheet is edited. Also, because you want to send emails, a simple trigger won't be enough (see restrictions of simple triggers here), you need to install a trigger. You can do this manually or programmatically. Here I provide the code to install the edit trigger programmatically. You would have to run this function once:
function createEditTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('sendEmails')
.forSpreadsheet(ss)
.onEdit()
.create();
}
This will make sendEmails run every time the spreadsheet is edited. You would have to put a condition that checks if the edited range is in column B. And you could do that if you use an Event object, which will be received by sendEmails as a parameter and that contains information about the context that fired the trigger.
Let's say that, as is usual, the event object is called e. You can access the range that was edited by doing e.range. And you can know the column that was edited if you do e.range.getColumn(). Also, you can know which row was updated if you do e.range.getRow() (which was your second problem).
With all this said, you would have to modify the function sendEmails the following way. You would have to change this:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRow = 232; //updated row in spreadhseet
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Rest of the code
}
To this:
function sendEmails(e) {
var range;
if (!e) range = SpreadsheetApp.getActiveRange();
else range = e.range; // Edited range
var sh = range.getSheet(); // Edited sheet
var dataRow = range.getRow(); // Edited row index
var column = range.getColumn(); // Edited column index
var yourSheetName = "Sheet1"; // Please change accordingly
// Check that edited sheet is the one you want to track change from
// and that edited column is B (index 2):
if (sh.getName() == yourSheetName && column == 2) {
// Rest of the code
}
}
It is very important that you write e as an argument for the function, otherwise the code won't know what e is. Also please bear in mind that this will only work if the spreadsheet is edited manually by a user, not programmatically by a script).
Also, in this sample, the sheet you want to track changes from is called Sheet1, please change it in the code if that's not the case.
Finally, regarding the HTML, I think you are missing some quotes in several places, and that's why it's not working properly. In this line, for example:
'<td width=400px" style="width:400px; background-color:yellow;">'
The 400px is missing the first ", it whould be width="400px".
I see a similar thing happening in this line:
'<span style="font-family:"Arial",sans-serif">Best</span> // ...
Here, you should be using escape characters (\"), otherwise, the script thinks you want to close a quote block when you want to open a new one. You should do something like this:
'<span style="font-family:\"Arial\",sans-serif">Best</span> // ...
I hope this is of any help.
I can help with 1 and 2. 3 is an email formatting question and that's normally a pain.
There's an onEdit(e) function which passes an object to the function. e.g. when I edit cell A7 to contain just the letter a, the object (e) contains this:
{
"range": {
"columnStart": 1,
"rowStart": 7,
"rowEnd": 7,
"columnEnd": 1
},
"value": "a"
}
Within the onEdit function, you could check (range.columnStart <= 2 && range.columnEnd >= 2) for changes to column B
You may be able to use the row value from the object above. Otherwise, you can find the last row in the sheet using var lastRow = sh.getLastRow()
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);
// ...
}
I added a select to a column of table cells with an ID. Using console.log I can see the select with the ID I gave it but when I try to set the value of the box using the ID I get a NULL reference error. What would the correct reference be for the box? Thanks.
JavaScript
function GetProc_Responce(r, responce) {
var table = "<tr><th>Emp</th><th>RA</th><th>PI</th><th>First Name</th><th>Last Name</th><th>Is A</th><th>Date Created</th><th>Date Modified</th></tr>";
strXml = new XMLSerializer().serializeToString(responce);
//console.log("returnString: " + strXml);
var oParser = new DOMParser();
oDOM = oParser.parseFromString(strXml, "text/xml");
//console.log(oDOM.getElementsByTagName("EmployeeID").length);
var l = oDOM.getElementsByTagName("EmployeeID").length;
for (i = 0; i <= l - 1; i++) {
a = oDOM.getElementsByTagName("Emp")[i];
_Emp = a.childNodes[0].nodeValue;
b = oDOM.getElementsByTagName("RA")[i];
_RA = b.childNodes[0].nodeValue;
c = oDOM.getElementsByTagName("PI")[i];
_PI = c.childNodes[0].nodeValue;
d = oDOM.getElementsByTagName("FirstName")[i];
_FirstName = d.childNodes[0].nodeValue;
e = oDOM.getElementsByTagName("LastName")[i];
_LastName = e.childNodes[0].nodeValue;
f = oDOM.getElementsByTagName("IsA")[i];
_IsA = f.childNodes[0].nodeValue;
g = oDOM.getElementsByTagName("DateCreated")[i];
_DateCreated = g.childNodes[0].nodeValue;
h = oDOM.getElementsByTagName("DateModified")[i];
_DateModified = h.childNodes[0].nodeValue;
table += "<tr><td>" +
a.childNodes[0].nodeValue + "</td><td>" +
b.childNodes[0].nodeValue + "</td><td>" +
c.childNodes[0].nodeValue + "</td><td>" +
d.childNodes[0].nodeValue + "</td><td>" +
e.childNodes[0].nodeValue + "</td><td>" +
//f.childNodes[0].nodeValue + "</td><td>" +
"<select id=\"s1\"><option value=\"0\">0</option><option value=\"1\">1</option></select>" + "</td><td>" +
g.childNodes[0].nodeValue + "</td><td>" +
h.childNodes[0].nodeValue + "</td></tr>";
document.getElementById('Proc').rows.item(3).cells(5).value = 1;
//OR
document.getElementById('s1').selectedValue = 1;
//NEITHER ONE WORKS
}
document.getElementById("Proc").innerHTML = table;
console.log(document.getElementById('Proc').rows(3).cells(5));
}
HTML
<div><center>
<table id="Proc"></table>
</center></div>
You must assign unique id values. Your code assigns all of them the id value s1 which is invalid in HTML.
Change your code as follows to assign s0, s1, s2 ... etc. For clarity I don't repeat the code that is not concerned:
for (i = 0; i <= l - 1; i++)
{
// ...
table += "<tr><td>" +
// ...
e.childNodes[0].nodeValue + "</td><td>" +
"<select id=\"s" + i + "\"><option value=\"0\">0</option><option value=\"1\">1</option></select>" + "</td><td>" +
// ...
}
You can access one of the select elements by its id with getElementById:
var element = document.getElementById('s' + i);
Where i is a number from 0 to the last one assigned in the loop.
You can get or set the value of a select element via its value attribute. For example, to set its value to 1, do:
document.getElementById('s' + i).value = '1';
Here we'll get div object
var div = document.getElementById('test');
Here we'll get table object
var table = div.getElementsByTagName('table')[0];
Here we'll add new select to td
table.rows[0].cells[0].innerHTML += '<select id="s2"></select>';
Search existed select (with id="s1")
var select_1 = table.rows[0].cells[0].getElementsByTagName('select')[0];
console.log(select_1);
Search all selects in td
var select_array = table.rows[0].cells[0].getElementsByTagName('select');
console.log(select_array);
https://jsfiddle.net/e59dzhsy/
document.getElementById('Proc').rows.item(3).cells(5) references a td, which does not have a value.
document.getElementById('s1') references the select box
you want document.getElementById('Proc').rows.item(3).cells(5).children[0] to reference the select
A better method would be to use some of the built in tag finding functions such as document.getElementById('Proc').rows[3].getElementsByTagName('select')[0]. Then you don't have to deal with what column the select is in. Of course, if you have more than one select on the row, then you'll need to do something different. At that point, I'd suggest adding class names to your selects so you can use document.getElementById('Proc').rows[3].getElementsByClassName('select1')[0]
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);
}}
});
I've got a piece of code that duplicates a <table> but in the process changes id's. It took hours but I eventually got this to happen with:
var lookFor = 'url' + parseInt(uploadCount);
++uploadCount; //used to create a unique id
var replaceWith = 'url'+parseInt(uploadCount);
var regex = new RegExp(lookFor, 'g');
var tableHTML = '<table class="user-url-table" style="opacity:0;" id="url' + uploadCount + '">' + $('table.user-url-table').first().html().replace(regex, replaceWith) + '</table>';
$(tableHTML).insertAfter($('table.user-url-table').last());
However, the following doesn't work:
var lookFor = 'url' + parseInt(uploadCount);
var tableHTML = '<table class="user-url-table" style="opacity:0;" id="url' + uploadCount + '">' + $('table.user-url-table').first().html() + '</table>';
++uploadCount;
var replaceWith = 'url'+parseInt(uploadCount);
var regex = new RegExp(lookFor, 'g');
tableHTML = $('table.user-url-table').first().html().replace(regex, replaceWith);
But shouldn't they do exactly the same job....? The first piece of code surely just does everything in one line, whereas the second forms the <table> and then changes all instances of the id in it.
There are two errors on the second code. First, when you do tableHTML = $('table.user-url-table').first().html().replace(regex, replaceWith); on the last line, you throw away the preparation you did. You override the value of tableHTML.
The second error is that the result is not appended to the document, like you did with insertAfter in the first code.
To make if work, replace the last line with $('table.user-url-table').after(tableHTML.replace(regex, replaceWith));. This will insert tableHTML with the replaced id's after the first table.
Another way, much simpler, of doing the same thing is this:
var firstTable = $("#url1 tbody").html();
var result = "";
for (i = 2; i < 10; i++) {
result += '<table class="user-url-table" style="opacity:0.2;" id="url'
+ i + '">' + firstTable.replace("url1", "url" + i) + '</table>';
}
$("#url1").after(result);
Fiddle: http://jsfiddle.net/bortao/ydEPr/