0

How can I have a button that when a user clicks it creates a Google Document based on a record's fields and after the document is created it also opens the document.

I have used the Document Sample in appmaker, I can create the Google Document, but I cannot find a way to open the URL of the Google Document (after it is created) using the same button that calls the function for creating the document.

For now, I have taken the same approach of the Document Sample to have a separate link in the application (which gets the URL of the Document after it is created). What I don't like of this solution is that a user needs to click in two different places.

Mauricio
  • 39
  • 5

2 Answers2

1

Edit: Changed to have the same onClick-to-open functionality as the Document Sample (no ad-block warnings), but with the OP's need to be in one button. Although the ideal solution would be to use javascript await, this works. The use of AppMaker page properties are unnecessary for this question. However I kept them in for simplicity of the matter.


I'll expand on Pavel's answer. For speed, you can make the document and go to the link before building the contents.

Set the name, immediately commit, open link, then have the script reopen and make the changes to that document.

I used Pavel's answer, changed the name of one function and added a parameter, and added one function. The rest is a copy and paste from the Document Sample.

widget's onClick event

if (!widget.root.descendants.CreateDocFormPanel.validate()) {
  return;
}

var pageWidgets = widget.root.descendants;
var props = widget.root.properties;

props.CreatingDoc = true;
props.DocumentUrl = null;
google.script.run
  .withSuccessHandler(function(documentUrl) {
    clearForm(pageWidgets);
    props.DocumentUrl = documentUrl;
    props.CreatingDoc = false;
    var win = window.open(app.pages.DocumentSample.properties.DocumentUrl, '_blank');
    win.focus();
  })
  .withFailureHandler(function(error) {
    console.error(JSON.stringify(error));
    props.CreatingDoc = false;
  })
  .createDoc(
    pageWidgets.NameTextBox.value,
    pageWidgets.ContentTextArea.value);

client script

/**
 * Clears form widgets after creating a Google Doc.
 * @param {Object} formWidgets - widgets of a form.
 */
function clearForm(pageWidgets) {
  pageWidgets.NameTextBox.value = null;
  pageWidgets.ContentTextArea.value = null;
}

server script

/**
 * Configures a Google Doc.
 * @param {string} id - id of the Google Doc.
 * @param {string} content - content to add to a Google Doc.
 * @return {string} URL of the configured Google Doc.
 */
function configDoc(id, content) {

  // Creating the document.
  var doc = DocumentApp.openById(id);
  var body = doc.getBody();

  // Insert a document header paragraph.
  var title =
    body.insertParagraph(0, 'A Document Created by an App Maker App');
  title.setHeading(DocumentApp.ParagraphHeading.HEADING1);

  // Insert a paragraph with provided content.
  body.insertParagraph(1, content);

  // Example of bold text.
  var boldText = body.appendParagraph('Example of bold text');
  boldText.setBold(true);

  // Example of italic text.
  var italicText = body.appendParagraph('Example of italic text');
  italicText.setItalic(true);
  italicText.setBold(false);

  // Example of colored text.
  var coloredText = body.appendParagraph('Example of colored text');
  coloredText.setItalic(false);
  coloredText.setForegroundColor('#388e3c');

  // Example of text with background color.
  var textWithBackground = body.appendParagraph('Text with background color');
  textWithBackground.setForegroundColor('#000000');
  textWithBackground.setBackgroundColor('#4fc3f7');

  // Add a paragraph with link with italic style.
  var link = body.appendParagraph('Learn more about Document Service');
  link.setLinkUrl(
    'https://developers.google.com/apps-script/reference/document/');
  link.setBackgroundColor('#ffffff');
  link.setItalic(true);

  doc.saveAndClose();
  return doc.getUrl();
}

/**
 * Creates a Google Doc.
 * @param {string} name - name of the Google Doc.
 * @param {string} content - content to add to a Google Doc.
 * @return {string} URL of the created Google Doc.
 */
function createDoc(name, content) {
  var doc = DocumentApp.create(name);
  doc.saveAndClose();
  configDoc(doc.getId(), content);
  return doc.getUrl();
}

More information can be found in the DocumentApp reference documentation.

A. Miller
  • 26
  • 3
  • Thank you. It works and opens a new tab with the Google Doc. After trying your suggestion I tried again Pavel's solution, it works too (I don't know what I was doing wrong). When I open the tab in the `withSuccessHandler` the browser asks to popups. Is there a way to avoid this? Why do the links created with AppMaker (like in the [Document Sample](https://developers.google.com/appmaker/samples/document/)) do not cause the browser to ask to allow popups? – Mauricio May 23 '18 at 01:02
  • It is browser's defensive mechanism against malicious scripts. Imagine if you enter some *bad* web site that has a script like this `while (true) { window.open(SPAM_URL_WITH_THIS_SCRIPT, '_blank'); }`. Number of open windows will grow very fast and your device will run out of memory and you'll not be able to stop it. So, you need explicitly allow sites you trust to open popups. – Pavel Shkleinik May 24 '18 at 16:48
  • Thanks so much Pavel, this is very helpful. Do you know why this does not happen when those new tabs are opened by clicking a link widget? In reality, I wanted to replicate that for a button so I don't have the user clicking at two elements. I could not find a way and I guess that's why the [Document Sample](https://developers.google.com/appmaker/samples/document/) was prepared with two steps (1 Generate file & 2 Download it) to avoid requesting permission to allow popups. – Mauricio May 25 '18 at 15:26
  • @Mauricio I edited the answer to resolve this issue. The problem you described happened when the window.open function was called from an outside script rather than from the widget's onClick function itself. – A. Miller Jun 14 '18 at 17:15
0

Try this snippet borrowed from this answer:

google.script.run
  .withSuccessHandler(function(documentUrl) {
    ...
    var win = window.open(documentUrl, '_blank');
    win.focus();
    ...
  })
  .withFailureHandler(function(error) {
    ...
  })
  .createDoc(...);
Pavel Shkleinik
  • 6,298
  • 2
  • 24
  • 36
  • Thank you Pavel, this works but the server script takes some time to send back the documentUrl so when I click the button, a blank page is opened as the documentUrl is taken as null. I tried waiting for the value putting a while loop on documentUrl, but it did work. The document that I generate is a two pager containing 10 records. Any suggestions for solving this? – Mauricio May 16 '18 at 06:42
  • Most likely you are doing something wrong. In the snippet above it is super important to execute open window code inside the `withSuccessHandler` callback using callback's parameter, other way it will not work. Fell free to update your question with actual implementation or put it in a comment below. – Pavel Shkleinik May 16 '18 at 15:08