0

I have a spreadsheet that takes input of stock symbols. I would like them to always be in ALL CAPS regardless of how they are typed in. This appears to require some scripting as there is no way to do this with a function unless a second copy of the column exists, which is not acceptable.

I have a solution which works, with one critical problem. The code is as follows:

function OnEdit(e) {
   var ss = e.source.getActiveSheet(),
       sheets = ['Trades', ''],
       ind = sheets.indexOf(ss.getName());
   if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1 ) {
       e.range.setValue(e.value.toUpperCase());
   }
}

It works great, and allows me to add as many tabs and columns to format as I wish. Unfortunately it also capitalizes the FORMULAS inside the cells, which is breaking formulas that use the importhtml() function, because it capitalizes the URL being requested.

So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?

EDIT: Thanks to @ocordova's comment, I thought I had something that would do the job well enough. Unfortunately it's behaving strangely... it works partly o some columns, and not at all on others. Here is my current code (slightly altered from earlier for clarity):

function onEdit(e){ 
   var activeSheet = e.source.getActiveSheet(),
       sheets = ['NEW Trades', ''],
       sheetIndex = sheets.indexOf(activeSheet.getName());
  if (sheetIndex === 0 && e.range.rowStart > 1 && e.range.columnStart >0  && e.range.getFormula() == '') {
    e.range.setValue(e.value.toUpperCase());
  }
}

Anyone have any ideas why some cells in some columns will capitalize as expected, and other cells in those same columns won't, and yet other columns won't capitalize at all, anywhere?

EDIT 2: My trouble appears to be related to, or a conflict with, Data Validation. The columns I'm trying to capitalize are fed by lists of values on another sheet. If the value was present previously in lower case, and then I applied the data validation to the column, the script will not capitalize the value. However if I select the appropriate, capitalized selection from the data validation list, and then re-type the same value in lower case, the script DOES kick in and capitalize. Very strange and confusing. I could be wrong about the conflict, but that's what it seems like to me.

EDIT 3: It's not related to data validation, because it's behaving the same way on a simple column that has no validation at all. If the value I had previously entered was already in lowercase, then typing it again in lowercase will not activate the script. BUT if I type the value in CAPS, then re-type it in lowercase, the script capitalizes it. Maybe some strange condition relating to when the script is triggered...?

JVC
  • 793
  • 3
  • 8
  • 21
  • Regarding the edits, it's not clear to me the scenario. Did you typed the unchanged spreadsheet values before or after that you edited your script? – Rubén Aug 08 '16 at 07:38
  • You got the scenario correct in your answer, which I will explore a little later today. – JVC Aug 08 '16 at 15:52

2 Answers2

2

If you don't want to capitalize if the cell contains a formula, you can use the method getFormula() and check if the cell contains a formula.

Returns the formula (A1 notation) for the top-left cell of the range, or an empty string if the cell is empty or doesn't contain a formula.

The code should look like this:

if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1  && e.range.getFormula() == '') {
  e.range.setValue(e.value.toUpperCase());
}

EDIT:

If I've understood you correctly, you're typing exactly the same value, example: if the value in the cell is México, and you delete all or some characters and inmediately type México again, in that scenario the old value and the new value are the same and the OnEdit() won't be fired. Another example is if you change the format of the value, that's another type of event.

If you want know how the event is considered, you can use an installable on change trigger:

function triggerOnChange(e) {
  MailApp.sendEmail('john.doe@gmail.com', 'Testing triggerOnChange', JSON.stringify(e));
}

Then in the Script Editor menu: Resources -> Current Project Triggers -> Add a new trigger -> ['triggerOnChange', 'From spreadsheet', 'On change']

On how to change the case of the formula's result, I think @Rubén has the right idea, but it will only work if the formula contains UPPER() in the first characters, and also since you're using the formula IMPORTHTML() using UPPER() will break it and maybe some other functions like array formulas, unless you use INDEX():

=INDEX(UPPER(IMPORTHTML(url, query, index)))

Another option could be Regular expressions, but I think it's a little risky considering all the combinations.

ocordova
  • 1,788
  • 2
  • 13
  • 20
  • This answer miss that the OP wants to change the case of the formula result. – Rubén Aug 08 '16 at 04:04
  • It's true that in a perfect world I would like to actually capitalize the formula result, but after a slight change to the way I'm using those formulas... this solution will do the job! I didn't know about `getFormula()` so thanks very much for pointing me to it! I'll accept this answer in a day or two, provided nobody else comes up with a way to actually capitalize the results of the formulas, which *would* be slightly better if possible. – JVC Aug 08 '16 at 04:17
  • Well after experimenting with this, it's only partially working and I've no idea why. Some columns react only on a few cells, other columns don't react at all. Will edit my question with my current code. – JVC Aug 08 '16 at 04:49
  • Interesting addition, thanks! I will explore and let you know what happens. – JVC Aug 08 '16 at 15:51
  • @ocordova: Even the code in my [answer](http://stackoverflow.com/a/38823237/1595451) has a lot of improvements opportunities, I think that you didn't understand it. Please consider to try it. – Rubén Aug 08 '16 at 22:10
  • @Rubén I totally understand your answer (: and as I mentioned above I think your answer was heading in the right direction, I really couldn't think of another way to achieve that, but since Jonathan mentioned he was using `IMPORTHTML()` (Maybe other array/custom functions I'm not aware of) I wanted to point out that some formulas would return String when evaluating with the typeof operator and could break them, change format, break urls... for example `IMPORTHTML()` but it all depends on Jonathan's spreadsheet values. But I'm glad your answer suit his needs using it As is :D – ocordova Aug 09 '16 at 15:02
  • Having IMPORTHTML, and any other built-in function as argument of UPPER should not be "any problem" but I didn't made extensive tests yet and I'm not planning to do them soon. By the way, the OP recently added a comment to my answer mentioning formatting problems on the resulting cell value. – Rubén Aug 09 '16 at 15:09
1

So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?

Consider to make a slight change in the OP approach: rather than capitalize all the cells content for any case, capitalize according the following conditions:

  1. If the cell value, including the values of cells that holds constants or formulas, is not a string then do nothing .
  2. If the cell value is a string
    • and the cell content is a constant, then change the case directly from the script.
    • and the cell content is a formula, then nest the original formula inside the built-in function UPPER.

Example:

function onEdit(e) {
  var range = e.range;
  var value = range.getValue();
  var sheet = range.getSheet();
  var sheetName = sheet.getName();
  if (sheetName === 'Sheet1' && 
      range.getRow() > 1 && 
      range.getColumn() > 1 && 
      typeof value === 'string') {
    if(!range.getFormula()) {
      range.setValue(value.toUpperCase());
    } else {
      if(range.getFormula().substring(0,6).toUpperCase() == '=UPPER') {
        return;
      } else {
        range.setFormula('=UPPER(' + range.getFormula().substring(1) + ')');
      }
    }
  }
}

Notes:

  • For simplicity the ind array was not included.
  • typeof e.value always returns 'string', so instead range.getValue(); is used.
Rubén
  • 34,714
  • 9
  • 70
  • 166
  • Hah very clever! Inserting `upper()` programatically... I wouldn't have thought of that. I'll play with this and see how it does! – JVC Aug 08 '16 at 15:50
  • Well, this works absolutely perfectly. Handles all my use cases, very nicely done! I'm going to award this as the best answer because it did in fact nail my needs out of the gate without any adjustments needed. Thanks for the help and for teaching me some new tricks! – JVC Aug 09 '16 at 01:42
  • Well shoot, I've hit a snag with your code after all, and I don't understand it. When the `upper()` function gets inserted into a column that contains a formula which generates a decimal number, that is then being displayed as a percentage (so .025 becomes 2.50%), the formula formatting breaks and suddenly becomes currency ($2.50)! I can't figure out why it would do that, and formatting the column as percentage doesn't do anything. Any idea why this would happen? – JVC Aug 09 '16 at 02:53
  • Since there are already a couple of answers, please post your followup question as a new question. Reference [What is the the best way to ask follow up questions?](http://meta.stackoverflow.com/questions/266767/what-is-the-the-best-way-to-ask-follow-up-questions) – Rubén Aug 09 '16 at 10:51
  • OK will do, I've explored this further and concluded that it's a separate issue altogether anyway. Thanks again! – JVC Aug 09 '16 at 16:19