1

I want to create a Google Doc with a Google Script and name the new doc from user input.

The code that follows does create the new doc (Web App attached to a button on a new Google Site). Now I want to add code that gets the song title from the user. I just have no idea how to do this after three days of looking.

Closest code I could find is: write data in google sheet using a web script app

But it is for Google Sheets, not Docs.

My code so far, which works to create the doc is:

Code.gs

function createNewLandscapeSong() {
  var doc = DocumentApp.create('Rename with song title');
  var title = "replace with song title"
  var url = doc.getUrl();
  var body = doc.getBody();
  var paragraph = body.insertParagraph(0, "");
  var text1 = paragraph.appendText("© replace with writer(s)");
  text1.setFontSize(8);
  var rowsData = [['PUT FIRST VERSE/CHORUS HERE.', 'PUT SECOND VERSE/NEXT CHORUS/BRIDGE/ETC HERE.']];
  var style = {};
  body.insertParagraph(0, title)
  .setHeading(DocumentApp.ParagraphHeading.HEADING3);
  table = body.appendTable(rowsData);
  style[DocumentApp.Attribute.BORDER_WIDTH] = 0;
  table.setAttributes(style);

  return {
   url: url,
   title: title
  };
}

Index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <input type="button" value="Create New Song Doc"
      onclick="google.script.run
          .withSuccessHandler(openNewDoc)
          .createNewLandscapeSong()" />
    <script>
       function openNewDoc(results){
           window.open(results.url, '_blank').focus();
       }
    </script>
  </body>
</html>
  </body>
</html>

So, I know somewhere in this code I need to add code that prompts the user to enter a song title and then I need to set that up as a variable and insert it as the name of the document and the title of the song (my "var doc" and "var title"). I just don't know how to do that.

Revised code based on Sandy's input:

Code.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

function createNewLandscapeSong(objArgs) {
  var docName = objArgs.docName;
  var songTitle = objArgs.songTitle;
  var songWriters = objArgs.songWriters;

  Logger.log('title: ' + title)

  var doc = DocumentApp.create(docName);

  var url = doc.getUrl();
  var body = doc.getBody();
  var paragraph = body.insertParagraph(0, "");
  var text = paragraph.appendText(songWriters);
  text.setFontSize(8);
  var rowsData = [['PUT FIRST VERSE/CHORUS HERE.', 'PUT SECOND     VERSE/NEXT CHORUS/BRIDGE/ETC HERE.']];
  var style = {};
  body.insertParagraph(0, songTitle)
  .setHeading(DocumentApp.ParagraphHeading.HEADING3);
  table = body.appendTable(rowsData);
  style[DocumentApp.Attribute.BORDER_WIDTH] = 0;
  table.setAttributes(style);

  return {
   url: url,
   title: title
  };
}

    Index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    Fill in fields below to name Google Lyric Document and add the song title and writers.<br><br>
    <input id="idNewDocName" type="text" placeholder="Google Doc Name"><br><br>
    <input id="idNewSongTitle" type="text" placeholder="Song Title"><br><br>
    <input id="idNewSongWriters" type="text" placeholder="Song Writers"><br><br>

    <button onclick="saveUserInput()">Create New Lyric Doc</button>

    <script>
      window.saveUserInput = function() {
      var docName = document.getElementById('idNewDocName').value;
      var songTitle = document.getElementById('idNewSongTitle').value;
      var songWriters = document.getElementById('idNewSongWriters').value;

    console.log('songTitle: ' + songTitle)

    google.script.run
      .withSuccessHandler(openNewDoc)
      .createNewLandscapeSong({docName:docName,songTitle:songTitle, songWriters: songWriters})

      }

       function openNewDoc(results){
           window.open(results.url, '_blank').focus();
       }
    </script>
  </body>
</html>
Bee Tee
  • 129
  • 2
  • 15

1 Answers1

0

You need a couple of input fields. This example shows one way to get values out of input fields. This example does not use a form tag because using a form tag can result in the browser tab being refreshed after the form submission with is confusing to people and is often not what they want.

To debug the code, in the Chrome browser, hit the f12 key to open the developer tools. After clicking the button you should see the value of the song title in the console log. Pass the data to the server code as an object. After running the code, from the code editor click the View menu, and choose Logs to see the log print out.

This shows one way to get user input from a Web App and pass it to the server code in Apps Script.

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>

    <input id="idNewDocName" type="text" placeholder="New Doc Name">
    <input id="idNewSongTitle" type="text" placeholder="New Song Title">

    <button onclick="saveUserInput()">Create New Song Doc</button>

    <script>
      window.saveUserInput = function() {
        var docName = document.getElementById('idNewDocName').value;
        var songTitle = document.getElementById('idNewSongTitle').value;

        console.log('songTitle: ' + songTitle)

        google.script.run
          .withSuccessHandler(openNewDoc)
          .createNewLandscapeSong({docName:docName,songTitle:songTitle})

      }

       function openNewDoc(results){
           window.open(results.url, '_blank').focus();
       }
    </script>
  </body>
</html>

Code.gs

function createNewLandscapeSong(objArgs) {
  var docName = objArgs.docName;
  var title = objArgs.songTitle;

  Logger.log('title: ' + title)

  var doc = DocumentApp.create(docName);

  var url = doc.getUrl();
  var body = doc.getBody();
  var paragraph = body.insertParagraph(0, "");
  var text1 = paragraph.appendText("© replace with writer(s)");
  text1.setFontSize(8);
  var rowsData = [['PUT FIRST VERSE/CHORUS HERE.', 'PUT SECOND VERSE/NEXT CHORUS/BRIDGE/ETC HERE.']];
  var style = {};
  body.insertParagraph(0, title)
  .setHeading(DocumentApp.ParagraphHeading.HEADING3);
  table = body.appendTable(rowsData);
  style[DocumentApp.Attribute.BORDER_WIDTH] = 0;
  table.setAttributes(style);

  return {
   url: url,
   title: title
  };
}
Alan Wells
  • 30,746
  • 15
  • 104
  • 152
  • I am getting following error: "TypeError: Cannot read property "docName" from undefined." on the line: "var docName = objArgs.docName;" I assume objArgs passes variables from the index.html script to the createNewLandscapeSong function, but I have never encountered objArgs before. (I will research on my end to beter undertsnad what it is doing.) – Bee Tee Feb 19 '19 at 16:49
  • Also, there is a close quote in the following line, but no open quote I can see: .createNewLandscapeSong({docName:docName,songTitle:songTitle, songWriters: songWriters})" It looks to me like this is the line that passes the variables on to the Code.gs (note, I added a writers field). Are these the values that are supposed to be picked up by the objArgs statement? – Bee Tee Feb 19 '19 at 17:23
  • If you run the `createNewLandscapeSong` function from the code editor, then nothing is passed into the function. `objArgs` will be assigned a value if it's called by clicking the button in the input form. I removed the double quotation mark on the end of the line. The `objArgs` argument is just a name given, like assigning a name to a variable. You could use any name. There is nothing special about the name. – Alan Wells Feb 19 '19 at 17:39
  • OK. Great. I understand. (BTW, thanks so much for your help.) So, I saved the revised script, Deployed as Web App, hit the update button, installed new URL address in the Google Site Button, published the site, refreshed the published site and clicked the button. I filled in the fields and clicked the Create New Doc button and nothing happens. When I check my Google Drive to see if a new doc has been created, it has not. New revised code posted in question. – Bee Tee Feb 19 '19 at 17:55
  • The url of the published Web App is always the same. When you publish a new version, the url doesn't change. There are two Web App urls, the "exec" version, and the "dev" (developement) version. To test your Web App without needing to republish, you can use the "dev" version. And you don't need to test it from your Google Site. You can click the "latest code" link to test the existing code. Also, from the code editor, click "View" and "Execution Transcript" to see if there was an error. Sometimes there may be an error that stops the code but that doesn't get display. – Alan Wells Feb 19 '19 at 18:17
  • Thanks for that explanation. Have wondered about all of that. Ran the scripts and checked the results in the Execution Transcript as you suggested. The doGet script seems to run fine but the Index.html throws an error: [19-02-20 01:46:56:457 PST] Starting execution [19-02-20 01:46:56:490 PST] Execution failed: TypeError: Cannot read property "docName" from undefined. (line 8, file "Code") [0.001 seconds total runtime] – Bee Tee Feb 20 '19 at 09:52
  • Note: You say above " objArgs will be assigned a value if it's called by clicking the button in the input form". This appears to be what is causing the error. objArgs is not being assigned the "docName" value, even though I have clicked the button on the input form. – Bee Tee Feb 20 '19 at 10:08
  • Figured it out. All had to do with the variable "title" versus "songTitle". Once I made all references in code the later, it worked. So, I will mark your answer as answered if that seems right to you. – Bee Tee Feb 20 '19 at 10:30
  • Glad you got it working. You can mark the answer as correct by clicking the green check mark. – Alan Wells Feb 20 '19 at 13:27
  • Hey @SandyGood, while this code is working and all is good, there's a section of it that I really don't understand: [function openNewDoc(results){ window.open(results.url, '_blank').focus();] The term "results" looks like it's a declared variable (dark blue), but I can't find it anywhere else in the script. Also, how is url being used and what does it do. Finally, what is "focus" doing? – Bee Tee Feb 22 '19 at 20:18
  • The function `openNewDoc` doesn't look like it is being used. I don't see anywhere that it is being called. The variable `result` would have been passed in, and would have needed to be an object with a key name `url` that was a link. The ` '_blank'` argument would have caused the link to be opened in a new tab. – Alan Wells Feb 22 '19 at 20:32
  • Hey @SandyGood, If I remove: function openNewDoc(results){ window.open(results.url, '_blank').focus(); }, what do I do about this line: .withSuccessHandler(openNewDoc) ? I assume I need the SuccessHandler in there. – Bee Tee Feb 23 '19 at 16:14
  • Sorry, it *is* being called from the success handler. The server code code does return an object with a `url` key. So, `openNewDoc(results)` should be getting called and run. I'm not sure what the chained `focus()` method is doing. I'm assuming it's trying to display the new window or browser tab that's opened. – Alan Wells Feb 23 '19 at 16:27
  • Based on what I read about "focus", it in effect closes sidebar if it was open (i.e., moves focus from sidebar to main sheet). @SandyGood – Bee Tee Feb 23 '19 at 16:30
  • So, since "url" is not a defined var, where does it get it? @SandyGood – Bee Tee Feb 23 '19 at 16:37
  • The very last line of function `createNewLandscapeSong` which is: `return { url: url, title: title };` An object is structured with elements that are composed of a key and a value. `{ key : value }` – Alan Wells Feb 23 '19 at 16:46
  • So, the var url from the gs is getting passed to the index? I ask this because I am trying to write a somewhat similar script [here](https://stackoverflow.com/questions/54835604/how-to-open-google-sheet-from-a-google-web-app) and if I include this "open" function, the script doesn't work. Without this little section, it does work, but the spreadsheet the script modifies is not getting opened. – Bee Tee Feb 23 '19 at 17:02
  • The object `{url: url,title: title}` from the gs file is being passed back to the HTML index file and put into the `openNewDoc(results)` function as the `results` variable. So, "Yes" – Alan Wells Feb 23 '19 at 17:07
  • Y'all that know what you are doing and help us newbies are awesome. Thanks so much for sharing your time and expertise. – Bee Tee Feb 23 '19 at 23:37