0

Broken down to its most elemental, what I want to do from a web app context is:

  • Ask for some data from user.
  • Display some data to user.
  • Ask for some more data from user.
  • Use all that data in a web app.

More specifically, I am trying to build a Google Script web app that does the following:

  1. Presents an html page where the user can input a user ID number.
  2. Takes that number and finds the last line on a spreadsheet belonging to that user.
  3. Displays that last line number to the user (this is the first point at which I am stumped—see below for what I have tried).
  4. Presents a 2nd html input page where the user can either accept the last line info displayed to them, or enter an alternate number (and some other info).
  5. All of that info is then used to create a Google Doc and add info about that Google Doc on a new row in a Google spreadsheet.

I have tried:

(a) Class PromptResponse [ui.prompt]
(b) alert(Prompt)
(c) showModalDialog
(d) show ModelessDialog

All of these failed as they apparently must be triggered from a bound app.

I considered the concept of having two doGet statements in a single webApp which led me to Linking to another HTML page in Google Apps Script, but that seems to deal with a two-page SINGLE html rather than two separate html pages (which is what I think I need).

I also considered using the Browser.msgBox in the Class CacheService but that produced the same context error as (a) thru (d) above.

Lastly, I thought about—rather than displaying the user ID number from (1) above—saving the variable and inserting it later in the script (i.e., loading it in (4) above). That led me to the CacheService. But I could not see how to make that work and in any event, it’s not really what I want to do.

GS

function doGet() {
  return HtmlService   
  .createTemplateFromFile('Index')
      .evaluate();
}
function getSongId(objArgs){
  // Get User's Catalog SS URL from Master Users List
  var userId = objArgs.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
      Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
      Logger.log("userCol = " + userCol);
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
      Logger.log("userSsUrl = " + userSsUrl);
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
  Logger.log("songId = " + songId);
  //some code here that displays songID to user

HTML "Index"

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
<center>    Enter your User ID below.
    <input id="userId" type="text" placeholder="User ID"><br><br>
    <button onclick="saveUserInput()">Continue</button>
    </center>

    <script>
      window.saveUserInput = function() {
        var user = document.getElementById('userId').value;

        console.log('userId: ' + userId)

        google.script.run

          .withSuccessHandler(openPrompt)
          .getSongId({user:user})

      }

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

songId Code

function getSongId() {
    var masterSSId = "ID";//This is the ID to the master users list SS.
    var userSS = SpreadsheetApp.openById(masterSSId);//Open
    var userSheet = userSS.getActiveSheet();
    var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
    var cell = userNamedRange.activate(); //activates range and first cell in range
    var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
    var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
    var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
    var ss = SpreadsheetApp.openByUrl(userSsUrl);
    var sheet = ss.getActiveSheet();
    var lastRow = sheet.getLastRow();
    var songId = lastRow+1;
}

As noted, I got "context" errors with everything I tried. BTW, I also created a web app that had 2 GS pages and 2 Index pages, and that just displayed both html pages on one page, and I still couldn't figure out how to display the User ID.

Finally, I spent a lot of hours, and used a lot of search terms, both at SO and the web in general trying to find someone else that has tackled this problem—and came up goose eggs.

Note: To respect "minimal, and verifiable," I have not included the script that asks for the 2nd set of info, but it is written and works.

Update: The following SO Question/Answer showed up to the right of this question: "Web apps+ remotely using script" after I posted it

It seems to in part solve my problem. At least it does display the user's User ID input, but I need it to display info I pull from a Google sheet based on the User ID (i.e., the songId). Using the doGet(e) approach, I still don't know where to put the getSongIdcode that gets the songId. I have added that code above.

Revised Code

gs

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

function getSongId(uObj) {
  var userId = uObj.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
    Logger.log("songId = " + songId);
  return songId;
}

html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <center>
Enter your User ID below.
<input id="userId" type="text" placeholder="User ID"><br>
<input type="button" value="Continue" onclick="saveUserInput()">
<div  id="results"></div>
</center>
<script>
      function saveUserInput() {
        var user = document.getElementById('userId').value;
        google.script.run
          .withSuccessHandler(function(hl){
            document.getElementById('results').innerHTML=hl;
          })
          .getSongId({user:user})
        }

    </script>
  </body>
</html>
Bee Tee
  • 129
  • 2
  • 15
  • Have you tried testing GetSongId() by itself? – Cooper May 28 '19 at 19:41
  • Is the SongId really the number of the last row +1 ? – Cooper May 28 '19 at 19:44
  • I suspect that you have some problems with getSongId function. Personally, I can't tell what you're trying to do there. – Cooper May 28 '19 at 20:05
  • GetSongId works fine in other places I have used it. The question to me is where do I put it for this application? It needs to take the UserId value entered by the user, so it seems like it should reside in the Index html file. I have tried it there within the – Bee Tee May 28 '19 at 21:12
  • The Javascript function is in the client. getSongID has to have access to the Spreadsheets so it's on the server and calling it via google.script.run is the right thing to do. – Cooper May 28 '19 at 21:17

1 Answers1

0

Try something simple first. Just to see that you can get the client and the server communicating:

html:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
Enter your User ID below.
<input id="userId" type="text" placeholder="User ID"><br>
<input type="button" value="Continue" onclick="saveUserInput()">
<div  id="results"></div>
<script>
      function saveUserInput() {
        var user = document.getElementById('userId').value;
        google.script.run
          .withSuccessHandler(function(hl){
            document.getElementById('results').innerHTML=hl;
          })
          .getSongId({user:user})
        }

    </script>
  </body>
</html>

Then use a simple getSongId() function:

function getSongId(uObj) {
  return uObj.user
}

I would use this sort of doGet()

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

You html doesn't have any scriptlets that need to be evaluated. It's not really a template.

Then test the getSongId by itself and once that works you can return it to the div and later if you wish you can create another page.

Cooper
  • 59,616
  • 6
  • 23
  • 54
  • Thanks Cooper. I will mess around with this. The innerHTML is a new wrinkle I have not seen. – Bee Tee May 28 '19 at 21:14
  • What is uObj and what is it doing? Does it get a value from somewhere/something? – Bee Tee May 28 '19 at 22:25
  • It's the object from this line in the Javascript: `.getSongId({user:user})` – Cooper May 28 '19 at 22:26
  • So it's the value the user entered (i.e., "101" for instance)? – Bee Tee May 28 '19 at 22:34
  • Also, what is the h1 doing? – Bee Tee May 28 '19 at 22:34
  • Also: where do I put the getSongId function? – Bee Tee May 28 '19 at 22:36
  • This is the Javascript `google.script.run.withSuccessHandler(function(hl){ document.getElementById('results').innerHTML=hl;}).getSongId({user:user})` The last part is the name of the function on the server. So the answer is in the server code. – Cooper May 28 '19 at 22:44
  • OK. Awesome. Got it and when I click the continue button, the 101 appears below. Will try to add in the actual getSongId code, which I assume will be on the server side too and precede the return uObj.user line? – Bee Tee May 28 '19 at 22:53
  • Got the getSongId code working. Had to add `var userId = uObj.user;` as first line. Now, the only problem is that I do not want to return the userId, I want to return the songId. The code I am using (per the log) is returning the correct row (438). What statement do I use to return it? I tried simply `return songId` and that does not work. – Bee Tee May 28 '19 at 23:04
  • Never mind. Forgot the ";" after `return songId` (stupid me). It's working. Thanks so much for your help. Now I am off to part 4 which is to add in the script to capture the remaining info, create the doc and update the spreadsheet. – Bee Tee May 28 '19 at 23:15
  • 1
    Try to break it up into smaller problems if you start to run into problems. It may help you to solve the problem and it helps us figure out more quickly where the current problem is. – Cooper May 28 '19 at 23:29
  • Cooper, could you take a look at my question at [https://stackoverflow.com/questions/56360165/can-one-use-if-else-statements-in-html-side-of-google-script-webapp]. I think you will have a better frame of reference on it than others from your help here. – Bee Tee May 29 '19 at 16:35
  • Yes you can use if else statements in Javascript on the client side? – Cooper May 29 '19 at 18:39
  • Hey @Cooper: I am trying to reuse some of this code. But I don't really know what is the h1 doing? – Bee Tee May 29 '19 at 19:27