Append html data with inline script html data and to print - javascript

I need to append table data with html inside script. And append data for print
but here the table data is only shows in the print mode.
html
<div>
<p>Your content here</p>
<table id="toPrint">
<tr>
<td>Neil D'zousa</td>
<td>112233445566</td>
</tr>
</table>
</div>
<div id="notForPrint">
print
</div>
script
function open() {
var w = window.print();
var htmlTable2 = '<tr>' + '<th>Name</th>'
+ '<th>Phone</th>'+ '</tr>';
var html = $("#toPrint").html();
var t=html;
$(t).append(htmlTable2);
$(w.document.body).html(t);
}
$(function() {
$("a#print").click(open);
});
if anyone knew about this please share your answer.
with regards ...

Demo
var htmlTable2 = '<tr>' + '<th>Name</th>'
+ '<th>Phone</th>'+ '</tr>';
var html1 = $("#toPrint").append(htmlTable2);
var t=html1;
$(t).append(htmlTable2);
window.print();
Try this. I tested in chrome. It works fine
EDIT:
Response to your req: You have to chack whether dom[name,etc] is already [resent
$('#domHeader').length > 0 means already present.
if(! $('#domHeader').length)
{
var htmlTable2 = '<tr>' + '<th>Name</th>'
+ '<th>Phone</th>'+ '</tr>';
var html1 = $("#toPrint").prepend(htmlTable2); //peter is correct
//var t=html1;
//$(t).append(htmlTable2);
}
EDITED DEMO
UPDATE FINAL

The following should do it. The headers should be at the top:
function open() {
var htmlTable2 = '<tr><th>Name</th><th>Phone</th></tr>';
var html1 = $("#toPrint").prepend( htmlTable2 );
window.print();
}
The rest of your code should work fine.

Related

Table rows are not rendering on separate lines

I am trying to render a table, wherein each row of data is on a separate line. From my understanding, this is the default behavior for how data between <tr></tr> tags is rendered. At least, that is how it is has always functioned for me.
This is the code I am using:
function GetLastTen(){
$.ajax({url: LastTen, success: function(result) {
var location = document.getElementById('l_ten');
location.innerHTML = "<table>\n";
function format(location,object){
location.innerHTML += '<tr>\n' +
'<td>' + object.id + '</a></td>\n' +
'</tr>\n';
}
$.each(result, function(elem){
format(location, result[elem]);
});
location.innerHTML += "</table>"
}});
}
The code obtains the proper data--there is nothing wrong with what I am getting from the API endpoint, but all the rows are on the same line.
I am using bootstrap 3.3.7 and the latest version of jQuery.
Try constructing a HTML string first into variable and setting the innerHTML once you are done:
var result = [{id:1},{id:2},{id:3}]
$(document).ready(function(){
var location = $("#l_ten")
var tableHTML = "<table>\n"
function format(object){
tableHTML += '<tr>\n<td>' + object.id + '</a></td>\n</tr>\n';
}
$.each(result, function(elem){
format(result[elem]);
});
location.html(tableHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="l_ten"></div>

How to pass values to an html page from google script

I have a google sheet, maintaining a list of projects, with some scripting running behind it. I have been able to add functionality to click an Add Project button which opens an HTML window for entering the information, and on submit, add a new record to the sheet.
Now I am working on a process to remove a record if the status is changed to Cancelled. What I would like to do is show an html window listing certain details of the project, and give the user a chance to either go back without cancelling the project, or enter some notes as to why it's being cancelled and then continue.
Where I am stuck is populating the html window with the details of the project. I have figured out one way to do it, but I know that this isn't the best way.
Google Script:
function onEdit(e) {
if(e.range.getColumn() == 9 && e.value == "Cancelled" && e.source.getActiveSheet().getName() == "Summary") {
var cancelSheet = ss.getSheetByName(e.source.getActiveSheet().getName());
var cancelRange = cancelSheet.getRange(e.range.getRow(), 1, 1, cancelSheet.getLastColumn());
var cancelRow = cancelRange.getValues();
openCancelDialog(cancelRow);
}
}
function openCancelDialog(x) {
var html = HtmlService
//.createHtmlOutputFromFile('Cancel')
.createHtmlOutput(
'<table><tr><td colspan = \"2\"><b>You are cancelling the following project:</b></td></tr>' +
'<tr><td>Project Name: </td><td>' + x[0][4] + '</td></tr>' +
'<tr><td>Project Number: </td><td>' + x[0][0] + '</td></tr>' +
'<tr><td>Project Category: </td><td>' + x[0][1] + '</td></tr>' +
'<tr><td>Business Owner: </td><td>' + x[0][17] + '</td></tr>' +
'<tr><td>Project Manager: </td><td>' + x[0][18] + '</td></tr>' +
'</table>'
)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Cancel a Project');
}
This way is writing the html directly in the gs. What I'd like to do is have a separate html page that gets created. That can be done with this method (and is how I'm creating the Add Project dialog elsewhere in the gs):
function openCancelDialog(x) {
var html = HtmlService.createHtmlOutputFromFile('Cancel').setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Cancel a Project');
}
This would be Cancel.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
<!-- Scripting to get my values? -->
</script>
</head>
<body>
<!-- Layout the window
Add a Comments section
Add a button to go back without cancel
Add a button to submit the cancel and update -->
</body>
</html>
But what I haven't figured out is how to pass the array from the openCancelDialog function to the html, so it cab be shown on the page..
I suspect that I need to add scripting to the Cancel.html file to get those values. But is there a way to send that array to the html while it's being created?
Kos's answer gave me some ideas on how I could work it out. That, as well as some additional reading, especially https://www.w3schools.com/js/js_json_intro.asp and the follow up sections, helped me figure this one out.
New js code:
function onEdit(e) {
if(e.range.getColumn() == 9 && e.value == "Cancelled" && e.source.getActiveSheet().getName() == "Summary") {
var cancelSheet = ss.getSheetByName(e.source.getActiveSheet().getName());
var cancelRange = cancelSheet.getRange(e.range.getRow(), 1, 1, cancelSheet.getLastColumn());
var cancelRow = cancelRange.getValues();
//openCancelDialog(cancelRow);
var aSheet = e.source.getActiveSheet().getName();
var column = e.range.getColumn();
var row = e.range.getRow();
Logger.log("Col: " + column + " Row: " + row + " Sheet: " + aSheet);
Logger.log(cancelRow);
}
Logger.log(e);
}
function openCancelDialog(row) {
var ui = SpreadsheetApp.getUi();
// get template
var template = HtmlService.createTemplateFromFile('Cancel');
var myJSON = JSON.stringify(row);
// pass data to template
template.data = myJSON;
// get output html
var html = template.evaluate();
// show modal window
ui.showModalDialog(html, 'Cancel a Project');
}
New HTML:
<!DOCTYPE html>
<html>
<body>
<table>
<tr><td>Number: </td><td id="number"></td></tr>
<tr><td>Name: </td><td id="name"></td></tr>
<tr><td>Category: </td><td id="category"></td></tr>
<tr><td>Business Owner: </td><td id="owner"></td></tr>
<tr><td>Project : </td><td id="manager"></td></tr>
</table>
<script>
var objII = JSON.parse(<?=data?>);
document.getElementById("number").innerHTML = objII[0][0];
document.getElementById("name").innerHTML = objII[0][4];
document.getElementById("category").innerHTML = objII[0][1];
document.getElementById("owner").innerHTML = objII[0][17];
document.getElementById("manager").innerHTML = objII[0][18];
</script>
</body>
</html>
I suspect there may be more elegant ways to do this, and probably even more "correct" ways. But this seems to be working for what I needed it to do, so I figured I'd post it in case someone else was looking.
Thank you
Use HtmlService.createTemplateFromFile:
function openCancelDialog(row)
{
var ui = SpreadsheetApp.getUi();
// get template
var template = HtmlService.createTemplateFromFile('Cancel');
// pass data to template
template.data = {
row: JSON.stringify(row)
};
// get output html
var html = template.evaluate();
// show modal window
ui.showModalDialog(html, 'Cancel a Project');
}
Cancel.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
var row = <?!=data.row?>;
//document.write(row);
</script>
</body>
</html>
Detailed template documentation: https://developers.google.com/apps-script/guides/html/templates
Here's another way to do it. I like to do it this way because I have a lot more control than I do with templates.
This is a script that I did when I was working on an email example script that is contained in a spreadsheet. This script is a little less complicated because it's just for giving the user the option for removing sent emails from the emailsetup page and archiving them on another page. It does it by creating html on the fly and collecting it as a string and then adding it to another page of html. I launch the html at the end of the script as a dialog that allows the users to select which emails to archive by checking checkboxes and clicking on a button called Archive Selected. I found it easier to put my javascript functions together in a standard html file and then run that through HtmlService first and append the string later.
Here's the script:
function archiveSelectedEmails()
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sht=ss.getSheetByName('EmailSetup');
var rng=sht.getDataRange();
var rngA=rng.getValues();
var s='<html><head><script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script></head><body>';
var s='';
for(var i=2;i<rngA.length;i++)
{
var dataA={};
for(var j=0;j<rngA[1].length;j++)
{
dataA[rngA[1][j]]=rngA[i][j];
}
var row=Number(i+1);
s+='<div id="row' + row + '"><input type="checkbox" name="email" value="' + Number(i+1) + '" />' + ' <strong>Row:</strong> ' + Number(i+1) + ' <strong>Name:</strong> ' + dataA.Name + ' <strong>Email:</strong> ' + dataA.Email + ' <strong>Subject:</strong> ' + dataA.Subject + ' <strong>DateSent:</strong> ' + Utilities.formatDate(new Date(dataA.DateSent), 'GMT-6', "M/dd/yyyy HH:mm:ss") + '</div>';
}
s+='<br /><input type="button" value="Exit" onClick="google.script.host.close();" /><input type="button" value="Archive Checked" onClick="getCheckedBoxes(\'email\');" />';
var html=HtmlService.createHtmlOutputFromFile('htmlToBody').setWidth(800).setHeight(250);
html.append(s);
SpreadsheetApp.getUi().showModelessDialog(html, 'Select Emails to Archive');
}
Here's the html file 'htmlToBody':
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
function getCheckedBoxes(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
var rowsToArchive = [];
for (var i=0; i<checkboxes.length; i++)
{
if (checkboxes[i].checked)
{
rowsToArchive.push(Number(checkboxes[i].value));
}
}
google.script.run
.withSuccessHandler(setResponse)
.archiveSelectedRows(rowsToArchive);
}
function setResponse(a)
{
var s='<br />Rows: ';
for(var i=0;i<a.length;i++)
{
if(i>0)
{
s+=', ';
}
s+=a[i];
var id='#row' + a[i]
$(id).css('display','none');
}
s+='<br />Total: ' + a.length;
google.script.run.displayMessage(s,'Archived Rows')
}
console.log('script here');
</script>
</head>
<body>
I took your project idea and ran with it a little.
These are the google scripts. You'll notice I started with the name of your function.
function openCancelDialog1()
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sht=ss.getSheetByName('Projects');
var rng=sht.getDataRange();
var rngA=rng.getValues();
var s='';
for(var i=1;i<rngA.length;i++)
{
var dataA={};
for(var j=0;j<rngA[0].length;j++)
{
dataA[rngA[0][j]]=rngA[i][j];
}
var row=Number(i+1);
s+='<div id="row' + row + '"><input type="checkbox" name="project" value="' + row + '" />' + ' <strong>Row:</strong> ' + Number(i+1) + ' <strong>Name:</strong> ' + dataA.Name + ' <strong>Project:</strong> ' + dataA.Description + '</div>';
}
s+='<br /><input type="button" value="Exit" onClick="google.script.host.close();" /><input type="button" value="Cancel and Archive Checked" onClick="getCheckedBoxes(\'project\');" />';
var html=HtmlService.createHtmlOutputFromFile('htmlToBody').setWidth(800).setHeight(250);
html.append(s);
SpreadsheetApp.getUi().showModelessDialog(html, 'Select Project to Cancel');
}
function archiveSelectedRows(rows)
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sht=ss.getSheetByName('Projects');
var dest=ss.getSheetByName('ArchivedProjects');
var rng=sht.getDataRange();
var rngA=rng.getValues();
var deleted=[];
for(var i=rngA.length-1;i>1;i--)
{
if(rows.indexOf(i+1)>-1)
{
deleted.push(Number(i+1));
rngA[i][4]=Utilities.formatDate(new Date(), 'GMT-7', 'M/d/yyyy')
dest.appendRow(rngA[i]);
sht.deleteRow(i+1);
}
}
var msg='Row Numbers Deleted = ' + deleted;
var title='Rows Deleted';
var timeout=10;
return deleted;
}
function displayMessage(msg,title)
{
msg+='<br /><input type="button" value="Exit" onClick="google.script.host.close()"; />';
var html=HtmlService.createHtmlOutput(msg).setWidth(400).setHeight(300);
SpreadsheetApp.getUi().showModelessDialog(html, title);
}
This is the htmlTobody file. It's been modified a bit for this situation.
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
function getCheckedBoxes(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
var rowsToArchive = [];
for (var i=0; i<checkboxes.length; i++)
{
if (checkboxes[i].checked)
{
rowsToArchive.push(Number(checkboxes[i].value));
}
}
google.script.run
.withSuccessHandler(setResponse)
.archiveSelectedRows(rowsToArchive);
}
function setResponse(a)
{
var s='<br />Row Numberss: ';
for(var i=0;i<a.length;i++)
{
if(i>0)
{
s+=', ';
}
s+=a[i];
var id='#row' + a[i]
$(id).css('display','none');
}
s+='<br />Total: ' + a.length;
google.script.run.displayMessage(s,'Canceled Rows')
}
console.log('script here');
</script>
</head>
<body>
And this is what my 'Projects' tab looks like. And I have a Projects tab and an ArchivedProjects tab. When I archive the projects they get copied into the ArchivedProjects sheet.

Always there is one extra empty page when printing

I'm working on an application to print a page. There is ALWAYS a blank extra page. I tried those solutions listed here but the problem is still present.
My print function is as follows:
// divID1 = the base, big div
// divID2 = some iframe inside divID1 (a table)
// value = the title of the print page
function printDiv3(divID1,divID2,value)
{
var func = "<style>td,th {padding:10px}
html, body{color:#000; height: 90%}
h2{font-size:18px;}
h4{font-size:16px;text-align:center;margin-bottom:-40px}
input,select{background-color:#000;border:thin solid #999999;}
.footer{position:absolute;bottom:0px;left:0px;right:0px,text-align:center;
width:100%;font-size:12px;margin-bottom:0px}
.sign{float:right;text-align:right;direction:rtl}</style>";
var header = "<h4>" + value
+ "</h4><img align='right' width='150' src='images/logo.png'><br><br><br><br>";
var footer = "<div class='footer' align='center'>Tel. address, etc </div> ";
var sign = "";
//Get the HTML of div + uframe
var divElements = document.getElementById(divID1).innerHTML
+ "<div style='width:100%;height:900px;position:absolute;top:325px'>"
+ window[divID2].document.body.innerHTML + "</div>" ;
//Get the HTML of whole page
var oldPage = document.body.innerHTML;
//Reset the page's HTML with div's HTML only
document.body.innerHTML =
"<html><head><title></title>" + func + "</head><body>"
+ header +"<table border=1>" + divElements + "</table>"
+ sign + footer +"</body></html>";
//Print Page
window.print();
//Restore orignal HTML
document.body.innerHTML = oldPage;
window.close();
}
My page structure is as follows:
<div id="example" > <!-- base div -->
<table border='1' width="100%" class="imagetable" id="imagetable1" >
...
</table>
<!-- the iframe -->
<table border='0' width="100%" class="imagetable">
<tr><td><div>
<iframe id="iframe_form" src="S.php" frameborder=0 style="width:100%;height:400px" ></iframe>
</div></td></tr>
</table>
<table>
...
</table>
</div>
Is the cause of problem that the div contains three consequent table?
I think you shouldn't do like this. The better ay is convert your html content in pdf.
If you stay in html you should respect print format (as A4) to expect what it work...
If you don't mastered the content of iframe, take a javascript screenshot ^^:
Using HTML5/Canvas/JavaScript to take screenshots
I hope it help you.
See you.

javascript : built an html form from json, but can't update the form

I have a javascript code that takes objects from json.
from this, i built an html string:
var htmlstr = "<table border=0>";
for (var i=0;i<jsonData.people.length;i++) {
htmlstr=htmlstr+"<tr><td>" + jsonData.people[i].name + "</td>";
htmlstr=htmlstr+"<td>"+ jsonData.people[i].cash + "</td>";
htmlstr=htmlstr+"<td><button onclick='changeCash(i)'>Update</button></td></tr>";
}
htmlstr=htmlstr+"</table>";
layer.addFeatures(features);
layer.events.on({ "featureselected": function(e) { updateMak('mak', htmlstr) } });
function changeCash(k) {
jsonData.people[k].cash=jsonData.people[k].cash+100;
}
The HTML page is as follows:
<script type="text/javascript">
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
alert("Mobile device detected."); }
function updateMak(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
} </script>
<div id="mak"> List of People </div>
Lets say this displays 10 people with their money.
If I click on one of their Update buttons, I think the json data is updated as intended. But I don't know how to verify it. The values in the form doesn't update the new value from the changeCash function.
How do I update the htmlstr and also update what's already displayed on screen?
Please advise.
When you generate htmlstr for the people cash
htmlstr=htmlstr+"<td>"+ jsonData.people[i].cash + "</td>";
You should also generate id for this td so that you can update the content from the function changeCash(k).
Something like
htmlstr=htmlstr+"<td id='peoplecash"+i+"'>" + jsonData.people[i].cash + "</td>";
And then in your changeCash function
function changeCash(k) {
jsonData.people[k].cash=jsonData.people[k].cash+100;
var peoplecash= document.getElementById("peoplecash"+k);
peoplecash.innerHTML = jsonData.people[k].cash;}

Pass string from one function to the next javascript

I've got a simple JavaScript client that pulls from a REST API to present some book data, however I seem unable to call the function createBookRow(bookid) and return the appropriate html string to the document ready function where it is called,
The output is currently being produced correctly as verified by the append to .row-fluid on the html page, ideas or suggestions welcome
function createBookRow(bookid)
{
$.get('http://mysite.co.uk/atiwd/books/course/'+bookid+'/xml', function(xml){
$(xml).find('book').each(function(){
var $book = $(this);
var id = $book.attr("id");
var title = $book.attr("title");
var isbn = $book.attr("isbn");
var borrowedcount = $book.attr("borrowedcount");
var html = '<div class="span3"><img name="test" src="http://covers.openlibrary.org/b/isbn/'+isbn+'-L.jpg" width="32" height="32" alt=""></p>' ;
html += '<p> ' + title + '</p>' ;
html += '<p> ' + isbn + '</p>' ;
html += '<p> ' + borrowedcount + '</p>' ;
html += '</div>';
$('.row-fluid').append($(html));
});
});
}
$(document).ready(function()
{
$.get('xml/courses.xml', function(xml){
$(xml).find('course').each(function(){
var $course = $(this);
var id = $course.attr("id");
var title = $course.text();
var html = '<div class="span12"><p>' + title + '</p><row id="'+id+'" >'+createBookRow(id)+'</row></div>' ;
$('.row-fluid').append($(html));
$('.loadingPic').fadeOut(1400);
});
});
});
The line
var html = '<div class="span12"><p>' + title + '</p><row id="'+id+'" >'+createBookRow(id)+'</row></div>' ;
should be just
var html = '<div class="span12"><p>' + title + '</p><row id="'+id+'" ></row></div>' ;
createBookRow(id);
createBookRow(id) function is making a get request to get some details, which happens asynchronously. Unless you explicitly mention it is a synchronous call(which is not advised).
I guess the functionality you need is to render some rows for course and in between you need books details displayed. In that case you need to explicitly say where your book row needs to be appended.
$('.row-fluid').append($(html));
The above code will always append book row at the end.
You aren't returning anything in the code you provided. You just append some HTML to a jQuery object. Try adding a return statement
return html;

Categories