2

I'm working on a Google Docs Add-On based on Google's Quickstart tutorial. I'm trying to change the workflow of the Add On in the tutorial to append a new page and then insert a translation on that new page rather than the line-by-line workflow.

I have a script working in single documents but I'm having a hard time moving it to the Add On architecture. I think it's something to do with passing selections from client-side JS to the server-side script doing the translation.

Here's the translate script

function translate(origin, dest, savePrefs) {
  Logger.log('Starting the script');
  if (savePrefs == true) {
    var userProperties = PropertiesService.getUserProperties();
    userProperties.setProperty('originLang', origin);
    userProperties.setProperty('destLang', dest);
    Logger.log(origin,dest);
  }

  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();

  // Add a page break for the translated material.
  body.appendPageBreak();

  // Get the number of elements in the document
  var elements = body.getNumChildren();
  Logger.log('Got the page elements');

  // Use the number to loop through each element in the document.
  for( var i=0;i<elements;i++) {
   var element = body.getChild(i).copy();
    var type = element.getType();
    Logger.log('Element Types were successful. Starting tests.');    

    // Test each type for a child element and run script based on the result
    // Images are nested in a paragraph as a child, so the second `if` makes
    // sure there is no image present before moving to the next paragraph.
    if( type == DocumentApp.ElementType.PARAGRAPH ){
      if(element.asParagraph().getNumChildren() != 0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
        var img = element.asParagraph().getChild(0).asInlineImage().getBlob();
        body.appendImage(img);
      } else if(element.asParagraph().getNumChildren() !=0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_DRAWING) {
        var drawing = element.asParagraph().copy();
        body.appendParagraph(drawing);
      } else {
        var text = element.asParagraph().getText();
        Logger.log(text);
        var spn = LanguageApp.translate(text, origin, dest);
        body.appendParagraph(spn);
      }
    } else if(type == DocumentApp.ElementType.TABLE) {
      element.asTable().copy();
      body.appendTable(element);
    } else if(type == DocumentApp.ElementType.LIST_ITEM) {
      var list = element.asListItem().getText();
      body.appendListItem(LanguageApp.translate(list, origin, dest));
    }
  }

The client-side JS is:

$(function() {
    $('#run-translation').click(loadPreferences);
    google.script.run(runTranslation)
  });

function runTranslation() {
    this.disabled = true;
    var origin = $('input[name=origin]:checked').val();
    var dest = $('input[name=dest]:checked').val();
    var savePrefs = $('#save-prefs').is(':checked');
    google.script.run
      .runTranslation(origin, dest, savePrefs);
  }

If I hard-code the languages to use in translation into the server-side script, it works. But as soon as I try to use variables from the radio buttons, it doesn't run. I don't see any errors in the console and I can't run scripts from the editor to check the logs. How can I debug this code?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Brian
  • 4,274
  • 2
  • 27
  • 55
  • Is this code directly copied and pasted? I ask because you are trying to call the server-side method named runTranslation, but in your server-side code the method is named translate. If this is the case thats why nothing is happening. Also are you checking the browser console or the script editor console? Any client side issues would appear in your browser console. – Jonathan Seed Aug 25 '15 at 18:36
  • Yeah, I had checked the browser console in the test sandbox as well as the script editor console, nothing was showing up. I think I have a fundamental misunderstanding of server-side functions vs client-side functions. – Brian Aug 26 '15 at 00:33

1 Answers1

3

Calling server-side functions from client Javascript

You've got a minor syntax error with google.run:

google.script.run(runTranslation)

It should be:

google.script.run
             .withFailureHander(failFunc) // Optional
             .withSuccessHander(succFunc) // Optional
             .serverFunction(optionalParams...);

The two Handler methods assign callback functions from your client-side JavaScript to be invoked in the case of success or failure of the server-side function. In both cases, the client-side function is provided as the only parameter.

The server-side function you want to communicate with is presented as if it is a method itself, with optional parameters to be passed across the divide.

The simplest case for you is:

google.script.run
             .translate(origin, dest, savePrefs);

(You had runTranslation in your posted code, but the server-side function is named translate()... I assume that's the right one.)

Now, this might will not take care of all your problems, so you wisely asked about debugging...

Debugging asynchronous client / server code in Google Apps Script

The provided debug environment isn't enough for debugging this sort of client / server exchange. There are also weaknesses in the Debugger for use with asynchronous execution - you can read more about that in Not seeing logs from onEdit trigger.

The simplest tool to get you debugging in this case would be to write logs to a spreadsheet

/**
 * Write message and timestamp to log spreadsheet.
 * From: https://stackoverflow.com/a/32212124/1677912
 */
function myLog( message ) {
  var ss = SpreadsheetApp.openById( logSpreadsheetId );
  var logSheet = ss.getSheetByName("Log") || ss.insertSheet("Log");
  logSheet.appendRow([ new Date(), message );
}

You can call this from your client-side Javascript thusly:

google.script.run.myLog( "CLIENT: " + message );

That's a basic approach, but you can extend it more through use of utility functions and the BetterLog library. See more about that in my blog entry Did you know? (You can log to a spreadsheet from client JavaScript!)

Community
  • 1
  • 1
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
  • 1
    This is fantastic. Thank you for such a detailed response and for a great method of debugging in Google Apps. Much more helpful as I tweaked this evening. Now it's running great. – Brian Aug 26 '15 at 00:51