2

I have set up an email to Google Sheets automation, where contents from a specific email automagically become new rows in a Google sheet. But one of the values is a full address (which is always one of only two addresses), and I would like it to be changed automatically to just the place name. So "address No.1" to "Place Name No.1", and "address No.2" to "Place Name No.2". The text is always in column E, and added to a new row.

Here is what I tried to use:

function onOpen() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("e1:e10");
var to_replace = "full long address";
var replace_with = "place name";
replaceInSheet(sheet,range, to_replace, replace_with);
}

function replaceInSheet(sheet, range, to_replace, replace_with) {
//Confirm
var ui = SpreadsheetApp.getUi(); 
var spread = SpreadsheetApp.getActiveSpreadsheet();

var result = ui.alert(
 "Will update " + to_replace + " to " + replace_with + " ",
 'Are you sure you want to continue?',
  ui.ButtonSet.YES_NO);

// Process the user's response.
if (result == ui.Button.YES) {

// User clicked "Yes".
spread.toast("Will update " + to_replace + " to " + replace_with + " ", "ALERT");

var data  = range.getValues();

var oldValue="";
var newValue="";
var cellsChanged = 0;

for (var row=0; row<data.length; row++) {
  for (var item=0; item<data[row].length; item++) {
    oldValue = data[row][item];
    newValue = data[row][item].replace(to_replace, replace_with);
    if (oldValue!=newValue)
    {
      cellsChanged++;
      data[row][item] = newValue;
    }
  }
}
range.setValues(data);
spread.toast(cellsChanged + " cells changed", "STATUS");
}
else {
// User clicked "No" or X in the title bar.
spread.toast("No action taken", "ABANDONED");
}
}
Roncho
  • 23
  • 1
  • 6
  • Welcome to StackOverflow. Could you edit the question to include the formula(s) you have tried so far please. – MandyShaw Aug 10 '18 at 16:11
  • OK! I'll do that now. – Roncho Aug 10 '18 at 16:26
  • 2
    I've added the code to my question. – Roncho Aug 10 '18 at 16:42
  • Thanks. Hopefully someone will be able to help you now. – MandyShaw Aug 10 '18 at 18:17
  • 1
    Check the errors you get in Stackdriver. You likely violate the restrictions that apply to simple triggers - you should review them in the Apps Script documentation. – tehhowch Aug 12 '18 at 18:08
  • @Roncho Hi. I'm looking at older questions that don't seem to have been resolved. How did you get on? Did you resolve your problem, or are you still looking for help? – Tedinoz Jan 09 '19 at 01:08
  • Hi @Tedinoz. I did not resolve my problem! And I am still looking for help. I am new to this site, and I don't really understand why my question hardly got any help. – Roncho Jan 10 '19 at 04:28
  • @Roncho No worries - I've got some ideas that will work, but best to canvas your work first. 1) Your code: have you run it?, did it work?, if not, what was the error message? 2)_tehhowch_ made a suggestion: did you follow that up? What results? 3)You've got two addresses to replace but the code only covers one. Why? 4)Why do you limit the range to row 50? 5) The code has got a lot of UI messages and confirmations. Do you really want/need those? – Tedinoz Jan 10 '19 at 09:19
  • @Roncho You've wondered why your question got little help; probably because you supplied your code but didn't explain (maybe, didn't know?) how/why it didn't work. It is very complex code but you didn't explain where the problem was. People expected more information from you. You are probably lucky the question wasn't closed as a duplicate of [this](https://webapps.stackexchange.com/questions/104157/auto-find-and-replace-in-google-sheets-with-scripts/104186). Anyhow, let's get this task done, and next time I reckon you'll be more careful about how you write your question. – Tedinoz Jan 10 '19 at 09:23
  • @Tedinoz, thank you very much for helping me out. I really appreciate it, as i have already given up on this, and resigned to having the full addresses in my spreadsheet, which in Japan are very long. I originally posted this question back in August, so I've forgotten what exactly happened when I tried running it. I'll try again later on today, and post the result here. Back in August, after searching a lot for how to do this, I ran across this code and tried tweaking it (with my very week knowledge in coding) to make it work for me, but with no avail. – Roncho Jan 11 '19 at 01:20
  • I don't know how to check for errors in stackdriver.I was I was trying to get it to work with one address first to see if the code works at all, and it didn't, so I haven't bothered with adding all the addresses (3 now). I didn't realize it was limited to only a certain range, as I am somewhat a retard when it comes to coding. Perhaps ignoring the code that I posted here, and writing a new one would be best? I'm not sure... – Roncho Jan 11 '19 at 01:25
  • And last, I'll try to explain what result I need a bit better, and hopefully that will help. There is a column in the spreadsheet for addresses. It gets them automatically from an email parser through Google maps. So that's why it shows the full address. The addresses are consistent, so I thought it would be possible to automatically replace a certain address with a pre decided string (the name of the branch). That's pretty much it. Again, thank you so much for your help. – Roncho Jan 11 '19 at 01:31
  • *UPDATE I have tried the code you suggested, and it seems to work partially. 1) It still asks me for permission to change the value, and I have to physically click "yes" for it to work. 2) It only seems to work when I open the document on my PC. I open this sheet a lot on my iPhone, and it doesn't seem to work there. 3) This is a shared spreadsheet, and I'm not sure the script will do its work on other users devices. 4) The current script only affects one string, and I am not sure how to add the other two adresses so they would also change to the place name. Thank you. – Roncho Jan 11 '19 at 02:06
  • 2
    @Roncho Try my suggested answer. – Tedinoz Jan 11 '19 at 02:33

1 Answers1

1

The OP's original code was most elegant (sourced from webapps) but over complicated for the task, and also not adapted to the replacing two addresses.

The following code is essentially a cut-down version of the OP original. A number of Logger.log() statements have been kept which will allow the OP (if &/or when necessary) to test values at different stages of the code.

The code logic is straightforward.
1) the addresses to be found and replaced are described as variables (var address01find and var address01replace, rinse and repeat for address02). The OP can edit this according to their taste.

2) get the last row in column E.

3) get the values for column E.

4) iterate through the values, row-by-row, testing for a value equal to either address01find or address02find. If the value is found, replace the value with address01replace and address02replace respectively.

5) after the loop, setValues for the entire data range. Most field values won't change, but those fields that were modified during the loop, will be updated to the revised value.

function onOpen() {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var MenuEntries = [{
        name: "Replace addresses",
        functionName: "replaceaddresss"
    }];
    ss.addMenu("Address Update", MenuEntries);
};

function replaceaddresss() {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();
    //Logger.log("DEBUG: sheet name: "+sheet.getSheetName());//DEBUG
    //Logger.log("DEBUG: range: "+range.getA1Notation());//DEBUG
    var Evals = ss.getRange("E1:E").getValues();
    var Elast = Evals.filter(String).length;
    //Logger.log("DEBUG: last row in E: "+Elast);//DEBUG
    var range = sheet.getRange(1, 5, Elast)
    //Logger.log("DEBUG: range: "+range.getA1Notation());//DEBUG
    var columnValues = range.getValues();
    var address01find = "Full Address 123, Tokyo, Japan";
    var address01replace = "Place Name No.1";
    var address02find = "Short Address 123, Tokyo, Japan";
    var address02replace = "Place Name No.2";
    //Logger.log("DEBUG: address #1: find: "+address01find+", replace with: "+address01replace);//DEBUG
    //Logger.log("DEBUG: address #2: find: "+address02find+", replace with: "+address02replace);//DEBUG
    for (i = 0; i < Elast; i++) {
        if (columnValues[i][0] === address01find) {
            columnValues[i][0] = address01replace;
        }
        if (columnValues[i][0] === address02find) {
            columnValues[i][0] = address02replace;
        }
    };
    range.setValues(columnValues);
}

Before and after

Before and after


UPDATE for OnEdit

This update looks at the scenario where data (i.e. the street address in Column E) is created by a script. The code is essentially the same except that the event range is known from onEdit, and it is only necessary to get the values, evaluate the addresses, and update the data IF the address value was changed.

Note: this script requires that it be created as an Installable OnEdit Trigger.

function oneditemailupdate(e) {

    // set up spreadsheet
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();

    // setup triggerdetector
    var trigger = 0;

    // User variables
    // identify the column to watch
    var addresscol = 5; // = Column E - this is the column to watch

    // Setup the old and new addresses
    var address01find = "Full Address 123, Tokyo, Japan";
    var address01replace = "Place Name No.1";
    var address02find = "Short Address 123, Tokyo, Japan";
    var address02replace = "Place Name No.2";

    // list onedit values for debug reporting and other use
    var debug_e = {
        authMode: e.authMode,
        range: e.range.getA1Notation(),
        source: e.source.getId(),
        user: e.user,
        value: e.value,
        oldValue: e.oldValue
    };
    //Logger.log("DEBUG: AuthMode: "+debug_e.authMode);// DEBUG
    //Logger.log("DEBUG: Range: "+debug_e.range);// DEBUG
    //Logger.log("DEBUG: Source: "+debug_e.source);// DEBUG
    //Logger.log("DEBUG: User: "+debug_e.user);// DEBUG
    //Logger.log("DEBUG: user email"+debug_e.user.getEmail());// DEBUG
    //Logger.log("DEBUG: Value: "+debug_e.value);// DEBUG
    //Logger.log("DEBUG: Old value: "+debug_e.oldValue);// DEBUG
    //Logger.log("DEBUG: AuthMode: "+debug_e.authMode+", Range: "+debug_e.range+", source: "+debug_e.source+", user: "+debug_e.user+", value: "+debug_e.value+", old value: "+debug_e.oldValue);//DEBUG

    // get the values for the range that was edited (e.range)
    var emailvalues = e.range.getValues();

    // evaluate email address value#1 and change value if necessary
    if (emailvalues[0][4] === address01find) {
        emailvalues[0][4] = address01replace;
        // set the trigger so that the range value can be updated
        trigger = 1;
        //Logger.log("DEBUG: Updated address01");//DEBUG
    }

    // evaluate email address value#2 and change value if necessary
    if (emailvalues[0][4] === address02find) {
        emailvalues[0][4] = address02replace;
        // set the trigger so that the range value can be updated
        trigger = 1;
        //Logger.log("DEBUG: Updated address02");//DEBUG
    }

    // if trigger value has been set to one, then update the values
    // Logger.log("DEBUG: Trigger value is "+trigger);//DEBUG
    if (trigger == 1) {
        e.range.setValues(emailvalues);
    }

}

UPDATE - FORM SUBMIT

Mea culpa. I managed to ignore the fact that the OP said that the spreadsheet was an email response sheet. Script executions and API requests do not cause triggers to run. So onEdit (whether as a Simple or Installable trigger) will not work.

  • The script needs to be installed as an Installable Script
  • The event type = "On form Submit"

This will return 'Form Submit' event data when the event object is called.

Note: the sheet name is now a variable. Otherwise the code is almost (but not quite) identical to the previous onEdit version.

function addressupdate(e) {

    // set up spreadsheet
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var formresponsesheet = "Form Responses 2";
    var sheet = ss.getSheetByName(formresponsesheet);

    // setup changetriggerdetector
    var trigger = 0;

    // User variables
    // identify the column to watch
    var addresscol = 5; // = Column E - this is the column to watch

    // Setup the old and new addresses
    var address01find = "Full Address 123, Tokyo, Japan";
    var address01replace = "Place Name No.1";
    var address02find = "Short Address 123, Tokyo, Japan";
    var address02replace = "Place Name No.2";

    // list onedit values for debug reporting and other use
    var debug_e = {
        authMode: e.authMode,
        range: e.range.getA1Notation(),
        namedValues: e.namedValues,
        triggerUid: e.triggerUid,
        values: e.values
    };
    //Logger.log("DEBUG: AuthMode: "+debug_e.authMode);// DEBUG
    //Logger.log("DEBUG: Range: "+debug_e.range);// DEBUG
    //Logger.log("DEBUG: named ValuesSource: "+debug_e.namedValues);// DEBUG
    //Logger.log("DEBUG: triggerUid: "+debug_e.triggerUid);// DEBUG
    //Logger.log("DEBUG: values: "+debug_e.values);// DEBUG

    // get the values for the range that was created (e.range)
    var emailvalues = e.range.getValues();

    // evaluate email address value#1 and change value if necessary
    if (emailvalues[0][4] === address01find) {
        emailvalues[0][4] = address01replace;
        // set the trigger so that the range value can be updated
        trigger = 1;
        //Logger.log("DEBUG: Updated address01");//DEBUG
    }

    // evaluate email address value#2 and change value if necessary
    if (emailvalues[0][4] === address02find) {
        emailvalues[0][4] = address02replace;
        // set the trigger so that the range value can be updated
        trigger = 1;
        //Logger.log("DEBUG: Updated address02");//DEBUG
    }

    // if trigger value has been set to one, then update the values
    // Logger.log("DEBUG: Trigger value is "+trigger);//DEBUG
    if (trigger == 1) {
        e.range.setValues(emailvalues);
    }

}

Tedinoz
  • 5,911
  • 3
  • 25
  • 35
  • Thank you very much for your help! You are an angel (: After adding your suggested code to the script editor, a button labled "Adress Update" has been added to the menu, and when pressed the addresses change to their corresponding place names. My question is: Is there no way to have this automation done in the background? As in, as soon as a new row is created, the address will change automatically. I have no problem with clicking that button every time I open the file, but it doesn't appear on the mobile version of Google Sheets, where I use it the most. What are your thoughts? – Roncho Jan 11 '19 at 11:39
  • Your code had a "do this when the spreadsheet opens" instruction. Not clearly flagged as an issue so reasonable to assume that it was what you wanted - another reason to word questions carefully. Instruction is called a "trigger"; ([quick summary of types under 'Getting Started' at the top of page](https://developers.google.com/apps-script/guides/triggers/)) and [more here](https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events). – Tedinoz Jan 11 '19 at 23:59
  • Instead of onOpen, you want onEdit **BUT** the process that updates your spreadsheet with the email details will not cause a "Simple" trigger to run (see "Restrictions" [here](https://developers.google.com/apps-script/guides/triggers/)). In your case, your email "system" won't trigger a "simple" onEdit. So, you'll need to create an "Installable" trigger ([succinct explanation in this answer](https://stackoverflow.com/questions/22333232/). I've got a [short guide](https://drive.google.com/open?id=1tlLdj8mRue6XB9s6tS_zRAZaP9Wbh4pY) if you're interested. – Tedinoz Jan 11 '19 at 23:59
  • @Roncho Oh. If you have found this answer useful, then you might "accept it. – Tedinoz Jan 12 '19 at 00:01
  • I have entered the code you suggested, and created an installable trigger. But when I ran the script it gave me this error - "TypeError: Cannot read property "authMode" from undefined. (line 21, file "Code")". Any idea how I can fix this? – Roncho Jan 13 '19 at 03:52
  • It's this line: var debug_e = { – Roncho Jan 13 '19 at 04:04
  • @Roncho 1) you can't run the script manually - that's why you got the error. 2) I am a fool; I forgot that the sheet was an Email Response sheet-onEdit won't be triggered regardless of how it is installed). 3) I updated the script to work when a new form response is received. Install this function as an Installable trigger, event type is "On form Submit". Note also that the sheet name is a variable that you should update. Lastly, the script will run when a form is submitted, and received into the spreadsheet. You can't run it manually, but you can submit a form to test it. – Tedinoz Jan 13 '19 at 08:49
  • Thank you again for your continuous help. I followed your instructions and it doesn't seem to work, but I think I might know why. At first I didn't pay attention to it, but you used the terms "On form Submit" and "form response" etc', but I just realized that it means data from responses on Google Forms. I haven't used Google forms for this. It's a booking system (for lesson cancellation/changing) on a website that sends an email with all the details. The email is then parsed, and using Zapier, sends the data to the spreadsheet. There is no use of Forms throughout the process. – Roncho Jan 13 '19 at 13:18
  • OR what I just said has nothing to do with anything, and the problem lies somewhere else. – Roncho Jan 13 '19 at 13:19
  • Just to clarify what I did - 1) I installed the trigger, but this time with "On form submit", 2) I added the updated code and changed the example addresses to the real ones, 3) I renamed the sheet "Form Responses 2" so it matches with the code. 4) I made a test reservation from the booking system which made it to the spreadsheet automatically, but the long address did not change. – Roncho Jan 13 '19 at 13:25
  • Doh. Yep, I “assumed” Google Forms. My bad. An update from Zapier is a problem because it does not trigger any Google script. What if you went back to the first answer (“replaceaddress”, delete the preceding ‘onOpen’ script) and install it as a “time-driven trigger”. That would at least automate the process, and it “should” work on mobile. – Tedinoz Jan 13 '19 at 21:56
  • It worked!!! Thank you so much for being patient. You made my life a lot easier (: – Roncho Jan 14 '19 at 02:25
  • I'm not the original asker but your answer was great! Thanks! – FiercestJim Oct 29 '20 at 16:53