I am building an app with App Inventor. I use a Webviewer to load a JavaScript code (see below) that displays, in a table, the content of a database stored in TinyDB.
So basically I have a table that looks like that:
I've tried to make the content of my table editable by adding this at the bottom of my script but without success: my table disappears.
<script>
function myFunction() {
document.getElementById("myTable").contentEditable = true;
}
</script>
Also I've also seen this page. But I can't find way to implement this .js in my App Inventor app.
Any idea how to make this work?
<body>
<div id="myTable"></div>
<script>
// get the table to display from the window.AppInventor object and split at new line
var urlArray = window.AppInventor.getWebViewString().split("\n");
var doc = document;
var fragment = doc.createDocumentFragment();
for(i=0;i<urlArray.length;i++){
var tr = doc.createElement("tr");
// split at comma
var rowArray = urlArray[i].split("|");
for(j=0;j<rowArray.length;j++){
if ( i == 0) { var td = doc.createElement("th"); }
else { var td = doc.createElement("td"); }
td.innerHTML = rowArray[j];
tr.appendChild(td);
fragment.appendChild(tr);
}
}
var table = doc.createElement("table");
table.appendChild(fragment);
doc.getElementById("myTable").appendChild(table);
</script>
</body>
Related
I'm currently trying to add column-level filtering to an HTML table, generated from a click event listener, using the TableFilter JavaScript library, however I'm receiving the following error in the console:
Error: Could not instantiate TableFilter: HTML table requires at least 1 row.
The code I'm using to generate the table is below; in essence I'm taking in an array of objects, then looping through them to create a header row, then data rows and then appending the table to a <div>. The table itself renders without issue, but I'm unable to attach filters - could anyone shed any light on why this error is occurring? I'd suspected it might be something to do with trying to add a filter to the table before the element had been rendered, but I couldn't see why that would be the case. I'm aware that the documentation for the library recommends adding a <script> tag under the table, and I've also tried this however I'm not sure how to do that correctly since the table doesn't exist until the click event takes place (hence adding it to the onclick function).
HTML
<html>
<head>
<script src="script.js"></script>
<script src="/TableFilter/dist/tablefilter/tablefilter.js"></script>
</head>
<body>
<button id="my-button">Create Table</button>
<div id="my-table-container">
<!-- table -->
</div>
<script>
button = document.getElementById('my-button');
button.addEventListener('click', renderTable);
</script>
</body>
</html>
JavaScript
const createTableFromObjectArray = (data, containerRef, tableRef) => {
// elements
let container = document.getElementById(containerRef);
let table = document.createElement('table');
table.setAttribute('id', tableRef);
// clear the DOM if the table is already present
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// create header
let headerRow = document.createElement('tr');
const colNames = Object.keys(data[0]);
colNames.forEach(name => {
let headerCell = document.createElement('th');
let headerText = document.createTextNode(name);
headerCell.appendChild(headerText);
headerRow.append(headerCell);
});
table.appendChild(headerRow);
// add rows to table
data.forEach(doc => {
let tableRow = document.createElement('tr');
Object.values(doc).forEach(value => {
let rowCell = document.createElement('td');
let cellText = document.createTextNode(value);
rowCell.appendChild(cellText);
tableRow.appendChild(rowCell);
});
table.appendChild(tableRow);
});
// add table to DOM and add filters
container.appendChild(table);
let tf = new TableFilter(table, {
base_path: '/TableFilter/dist/tablefilter/'
});
tf.init();
}
const renderTable = () => {
const data = [{'Name': 'John', 'Eyes': 'Blue', 'Hair': 'Brown'}];
const containerRef = 'my-table-container';
const tableRef = 'my-table';
createTableFromObjectArray(data, containerRef, tableRef);
}
This is my final project in view mode :
https://drive.google.com/open?id=1gOOb3hND3q2v0vTy8SfPVHFiCnTkJPR5
each row corresponds to a Google Doc project so when I modify in the row it will modify the corresponding Doc and when I click to see the document in the same window when I modify if then click the submit button I will change the row so I have an interactivity 100% with only the trigger onEdit(e) which will call function Edit(e) and openDialog(e).
The problem is that it can overwrite the Google Doc file as in the image. The problem comes from function
onEdit(e){
Edit(e);
openDialog(e); // tick to see the project in the same window and modify it transfer to the row
}
if I put openDialog(e); in comment if for instance I delete a text field in the row it will modify it correctly and with the openDialog(e) it will overwrite it. I've tried to put the openDialog code into the Edit(e) code as in the New.gs file but it's unsuccesful and close the doc https://script.google.com/d/1bV_eJONvUAbHyO6OB04atfm_sb5ZO8LWNoQ23fxf0lFnRzHRSwW7hsQc/edit?usp=sharing Do you have an idea to solve it? Thank you very much :) Separately they function very well. Together no it can overwrte the file so I don't know I need to close the Google Doc at very time because I open it 2 times?
It's the column J; I set a trigger to view the Google Doc in the same window and I can modify inside submit button and will change the row (this is the openDialog corresponding part)
Edit : sorry this is the code
var TITLE = 'Show Google Doc';
var SPREADSHEET_ID = "17ssKkCAoPUbqtT2CACamMQGyXSTkIANnK5CjbbZ1LZg"; // = assign your spreadsheet id to this variable
var column_name_project ;
var column_code_project ;
var column_chef_project;
var column_service ;
var column_other_services ;
var column_type_of_project ;
var column_perimeter ;
var column_date_project ;
var COLUMN_URL ;
var COLUMN_VIEW_Google_Doc;
/** will return the number of the column correspondant **/
function find_columns_in_projet(){
//search the columns
}
function onEdit(e){
Edit(e);
// openDialog(e);
}
function Edit(e) {
find_columns_in_projet();
var tss_bis = SpreadsheetApp.openById(SPREADSHEET_ID);
var sheet_bis = tss_bis.getSheets()[0];
var numRows_bis = sheet_bis.getLastRow();
var lastColumn_bis = sheet_bis.getLastColumn();
//from the second line car the first line we have the headers
var data_sheet = sheet_bis.getRange(1,1,numRows_bis,lastColumn_bis).getDisplayValues();
//Access the range with your parameter e.
var range = e.range;
var row = range.getRow();
var column = range.getColumn();
if( e.range.getColumnIndex() != COLUMN_URL + 1 ) {
var URL = data_sheet[row-1][COLUMN_URL-1];
Logger.log('Le URL est bien : ' , URL);
var body = DocumentApp.openByUrl(URL).getBody();
Logger.log('The body is ' + body );
if(body)
{... code to write the information from the spreadsheet to the Google Doc
}
}
}
/** every row in the current Sheet corresponds to a Google Doc Document **/
/** to see the Google Doc in the same page click in colum J and be able to modify the Google Doc 8 rows table inside
By clicking the button Submit it will transfer the information with what you have changed to the row of the corresponding project int the Sheet **/
function openDialog(e) {
/** columns in the Spreadsheet that are lines in the Google Doc table **/
/** find_columns_in_projet();
/** the good Sheet **/
if( ( e.range.getSheet().getName() === "Sheet1" ) && ( e.range.getColumnIndex() == COLUMN_VIEW_Google_Doc ) ) {
if( e.value === "TRUE" ) {
try {
//Get Google Doc body
/** the URL that is in the column I **/
var URL = e.range.offset(0,-1,1,1).getValue();
e.range.setValue("FALSE");
// Add this line
var ui = HtmlService.createTemplateFromFile('ModeLessDialog');
ui.body = URL; // Pass url to template
ui.insert = e.range.getRow() ;
ui = ui.evaluate().setWidth(1000).setHeight(500);
SpreadsheetApp.getUi().showModalDialog(ui, 'Show Google Doc');
}
catch(err) {
Logger.log(err);
}
}
}
}
function submitDoc(url,insert) {
/** the Spreadsheet need for getRange insert position **/
var tss_bis = SpreadsheetApp.getActiveSpreadsheet();
var sheet_bis = tss_bis.getSheets()[0];
find_columns_in_projet();
try {
Logger.log(url);
var google_doc = DocumentApp.openByUrl(url) ;
var body = google_doc.getBody();
if(body) {
code to write the information from the Google Doc into the Spreadsheet by button submit
}
Logger.log(body);
}
return true;
}
catch(err) {
Logger.log(err);
}
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<iframe id="srcFrame" src="<?= body ?>" name="<?= insert ?>" width="1000" height="400"></iframe>
<input type="button" value="Sumit changes to the Spreadsheet" onclick="submitDoc()">
<script>
function submitDoc() {
var url = document.getElementById("srcFrame").src;
var insert = document.getElementById("srcFrame").name;
google.script.run.submitDoc(url,insert);
google.script.host.close();
}
</script>
</body>
</html>
(This is my first question here and I am new to programming)
I am stuck on a problem and I tried to take something from here:
http://jsfiddle.net/4pEJB/
Dynamically generated table - using an array to fill in TD values
The function I created receive two vectors and creates a table with 2 columns, one for each vector, and lines = vector.length.
The function works fine, it seems to create the table as I need, but it doesn't show the table created on the browser screen after button click. By using some 'alert()' on the for loops I was able to verify that it uses the correct data.
In fact, when the button is clicked, it calls another function that processes some data and passes two vectors on this function I am showing here, but this part works well.
Here is the HTML part:
<div class="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
And here is the JavaScript part:
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
tableDiv.appendChild(table);
}
When the function finishes the table feed, it stops on tableDiv.appendChild(table);
Any advice or suggestions will be greatly appreciated! (I speak portuguese, I am sorry for some errors)
EDIT: it's possible to avoid the increment on the number of table rows that occurs every time we click the button (the solution provided generates one new table under the previous table). To solve this, I just added this line on the beggining of the function code (need to put the button outside the div and let the div empty, otherwise it will hide the button):
document.getElementById("tableDiv").innerHTML = "";
you are capturing by id, but you set up a class.chang it to id
<div id="tableDiv">
and append the tableBody into table.You're populating the table body with rows, but never appended the body into the table element.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody) // append tableBody into the table element
tableDiv.appendChild(table);
}
<div id="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
You try to append the var table to the tableDiv but the var table is stil empty.
Before append the tableBody to the var table and it will work.
Use id instead of class in your HTML Markup
<div id="tableDiv">
and then use the following code.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody);
tableDiv.appendChild(table);
}
First you are accessing the div using id whereas the node is defined with a class.
Secondly, you have to append the body to the table node first, and then append the table to the div selected.
Try this code snippet to move on.
I have a SharePoint 2010 list of around 198 items. For the first 30 items Text to Html Javascript function successfully converts text code to Html but when I am trying to select next 31 items and go ahead using the pagination the function does not able to convert Html and display only text codes. Does anyone please who have the code handy to make this work? Below is the code used in SharePoint 2010. Thank you.
<script type="text/javascript">
function TextToHTML(NodeSet, HTMLregexp) {
var CellContent = "";
var i=0;
while (i < NodeSet.length){
try {
CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
}
catch(err){}
i=i+1;
}
}
// Calendar views
var regexpA = new RegExp("\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*");
TextToHTML(document.getElementsByTagName("a"),regexpA);
// List views
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// This function is call continuesly every 100ms until the length of the main field changes
// after which the convert text to HTML is executed.
//
var postElemLength = 0;
function PostConvertToHtml()
{
if (postElemLength == document.getElementsByTagName("TD").length)
{
setTimeout(PostConvertToHtml,100);
}
else
{
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
}
}
// Grouped list views
ExpGroupRenderData = (function (old) {
return function (htmlToRender, groupName, isLoaded) {
var result = old(htmlToRender, groupName, isLoaded);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// start the periodic callback to check when the element has been changed
if(isLoaded == 'false')
{
postElemLength = document.getElementsByTagName("TD").length;
setTimeout(PostConvertToHtml,100);
}
};
})(ExpGroupRenderData);
// Preview pane views
if (typeof(showpreview1)=="function") {
showpreview1 = (function (old) {
return function (o) {
var result = old(o);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
};
})(showpreview1);
}</script>
Below is the generated text code which needs to be converted to Html. Thanks.
="<div style='position:relative;display:inline-block;width:100%;'>
<div style='width:100%;display:inline-block;text-align:center;border:1px solid "&Project_Status_clr&";position:absolute;color:"&Project_Status_clr&";'> "&Project_Status&"
</div>
<div style='display:inline-block;width: 100%;background-color:"&Project_Status_clr&";text-align:center;border:1px solid;z-index:-1;filter:alpha(opacity=20);opacity:0.2;'>"&Project_Status&"
</div>
</div>"
When generating a string of HTML in a calculated column in SharePoint 2010, you can change the calculated column's value type to "Number" to get the HTML to render in the list view.
I am working on javascript.
I have some API calls(Using Ajax) in my code.
There is a button in my UI
on click of this button I am making some API call using AJAX and displaying below HTML UI:
In the table above there are 2 rows. Now if I close this popup and then again click on User Dashboard button it will append those 2 rows again in the table. I dont want to append those rows again.
My code to form table using AJAX response looks like below:
getUserAccountDetailsCallback : function(userid, appid, response){
if(response != "")
{
var res = JSON.parse(response);
var totalNoOfApps = document.getElementById('totalSites');
var totalNoOfSubscriptions = document.getElementById('totalSubscribers');
totalNoOfApps.innerHTML = res.totalNoOfApps;
totalNoOfSubscriptions.innerHTML = res.totalNoOfSubscriptions;
if(res.subscriptionsForCurrentAppId.length > 0){
for(var i = 0; i < res.subscriptionsForCurrentAppId.length; i++){
var td1=document.createElement('td');
td1.style.width = '30';
td1.innerHTML=i+1;
var td2=document.createElement('td');
td2.innerHTML=res.subscriptionsForCurrentAppId[i].gatewayName;
var td3=document.createElement('td');
td3.innerHTML=res.subscriptionsForCurrentAppId[i].priceCurrencyIso;
var td4=document.createElement('td');
td4.innerHTML=res.subscriptionsForCurrentAppId[i].amountPaid;
var date = new Date(res.subscriptionsForCurrentAppId[i].subscribedDate);
date.toString();
var td5=document.createElement('td');
td5.innerHTML=date.getMonth()+1 + '/' +date.getDate() + '/' + date.getFullYear();//res.subscriptionsForCurrentAppId[i].subscribedDate;
var td6=document.createElement('td');
td6.innerHTML=res.subscriptionsForCurrentAppId[i].transactionId;
var td7=document.createElement('td');
td7.innerHTML=res.subscriptionsForCurrentAppId[i].active;
var tr=document.createElement('tr');
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tr.appendChild(td5);
tr.appendChild(td6);
tr.appendChild(td7);
var table = document.getElementById('tbl');
table.appendChild(tr);
}
}
}
}
Please help. Where I am doing wrong.
add thead and tbody
<table>
<thead><tr><th>#</th><th>Gateway.....</tr></thead>
<tbody id="tBodyId"></tbody>
</table>
remove the content of tbody before appending
like this:
var tBody = document.getElementById("tBodyID");
while (tBody.firstChild) {
tBody.removeChild(tBody.firstChild);
}
if(res.subscriptionsForCurrentAppId.length > 0){