1

I'm looking to get some help with Google Docs and Scripts. I have a workflow list that shows names of employees assigned to a task. There is also another field that indicates employees off of the day. I would like a script that can be run that would strikethrough the names of the individuals identified as off for the day. There could be multiple individuals off, so it would need to include a series of cells to reference. Results to look something like this.

[Requested outcome1

The problem I am running into is I cannot successfully find any code for even a starting point. I have seen pieces here and there, but nothing that is complete enough for me to even determine a starting point. I'm reasonably technical, but am not familiar with script writing. I have been unable to find a decent writeup on something like this so am requesting assistance if possible. Thank you!

Here is the code attempted where I am getting illegal argument on Line 27 currently. I will have it linked to a button. The individual in charge of updating the sheet daily will make all the daily changes, then once done click to button to clear any strikethrough and initiate based on new names input, if there are any.

Sample sheet link here.

https://docs.google.com/spreadsheets/d/1chSTd7Zy1qqu32qu4spSJJanwTI1SnH6rJtoMxb7iEc/edit?usp=sharing

function myFunction() 
{
  var spreadsheet = SpreadsheetApp.getActive();
  spreadsheet.getRange('B:B').activate();
  spreadsheet.getActiveRangeList().setFontLine(null);



  const sheetName = "Sheet1";  // Please set the sheet name.

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const range = sheet.getRange('B2:B')

  const textsForStrikethrough = sheet.getRange("A15:A20").getValues().flat(); // Added

    const modify = range.getValues().reduce((ar, e, r) => {
    e.forEach((f, c) => {
      textsForStrikethrough.forEach(g => {
        const idx = f.indexOf(g);
        if (idx > -1) ar.push({start: idx, end: idx + g.length, row: r, col: c});
      });
    });
    return ar;
  }, []);
  const textStyle = SpreadsheetApp.newTextStyle().setStrikethrough(true).build();
  const richTextValues = range.getRichTextValues();
  modify.forEach(({start, end, row, col}) => richTextValues[row][col] = richTextValues[row][col].copy().setTextStyle(start, end, textStyle).build());
  range.setRichTextValues(richTextValues);
}
5
  • 1
    Welcome. You do NOT need script for that. It can be done using conditional formatting. Please read how to ask here and here Commented Feb 25, 2021 at 21:35
  • 1
    Conditional formatting applies to the entire cell, I'm looking for it to apply to the text in question not the entire cell. Commented Feb 25, 2021 at 22:13
  • And I have searched and been unable to find anything concerning this. I'm at a total loss with it. Commented Feb 25, 2021 at 22:38
  • You are correct. Hasty comment. Commented Feb 25, 2021 at 22:49
  • If you want to learn the best place to start are the Tutorials - from there, look into how Apps Script implements Rich Text - its not completely straightforward though, and is quite a custom application, so its no big surprise that there is no ready made script for it. Great excuse to start learning JavaScript via Apps Script. Commented Feb 26, 2021 at 13:14

1 Answer 1

1

I believe your goal as follows.

  • You want to reflect the strikethrough to the partial text in a cell using Google Apps Script as follows. (The sample image is from your question.)

In this case, I would like to propose to use RichTextValueBuilder. The sample script is as follows.

Sample script:

function myFunction() {
  const textsForStrikethrough = ["John"];  // Please set the texts you want to reflect the strikethrough.
  const sheetName = "Sheet1";  // Please set the sheet name.

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const range = sheet.getDataRange();
  const modify = range.getValues().reduce((ar, e, r) => {
    e.forEach((f, c) => {
      textsForStrikethrough.forEach(g => {
        const idx = f.indexOf(g);
        if (idx > -1) ar.push({start: idx, end: idx + g.length, row: r, col: c});
      });
    });
    return ar;
  }, []);
  const textStyle = SpreadsheetApp.newTextStyle().setStrikethrough(true).build();
  const richTextValues = range.getRichTextValues();
  modify.forEach(({start, end, row, col}) => richTextValues[row][col] = richTextValues[row][col].copy().setTextStyle(start, end, textStyle).build());
  range.setRichTextValues(richTextValues);
}

Result:

When above script is run, the following results are obtained.

Input situation:

This is the sample input situation before the script is run.

enter image description here

Output situation 1:

In this case, const textsForStrikethrough = ["John"]; is used for the input situation.

enter image description here

Output situation 2:

In this case, const textsForStrikethrough = ["John", "Amy"]; is used for the input situation.

enter image description here

Note:

  • In this sample script, all values are retrieved from the sheet and search the texts and reflect the strikethrough. So when you want to use this script to the specific range, please modify const range = sheet.getDataRange(); for your situation.
    • For example, from your sample image, when you want to use this script to the column "B", please modify it to const range = sheet.getRange("B1:B" + sheet.getLastRow());.

References:

Added:

About your following 2nd question,

This is perfect! Only other request I have, is how would we modify it to where it is referencing a series of other cells to lookup the names? The list of names changes daily, so looking to have all inputs be able to update by a simple change of the names on the sheet rather than modifying the code. So say the names could be input in cell A10:A15. Pulling that list of names and updating the "textsForStrikethrough" logic.

in this case, I think that at first, how about retrieving the values of cells "A10:A15", and use them as textsForStrikethrough?

Sample script 2:

function myFunction2() {
  // const textsForStrikethrough = ["John"];  // Please set the texts you want to reflect the strikethrough.
  const sheetName = "Sheet1";  // Please set the sheet name.

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const range = sheet.getDataRange();
  
  const textsForStrikethrough = sheet.getRange("A10:A15").getValues().flat(); // Added
  
  const modify = range.getValues().reduce((ar, e, r) => {
    e.forEach((f, c) => {
      textsForStrikethrough.forEach(g => {
        const idx = f.indexOf(g);
        if (idx > -1) ar.push({start: idx, end: idx + g.length, row: r, col: c});
      });
    });
    return ar;
  }, []);
  const textStyle = SpreadsheetApp.newTextStyle().setStrikethrough(true).build();
  const richTextValues = range.getRichTextValues();
  modify.forEach(({start, end, row, col}) => richTextValues[row][col] = richTextValues[row][col].copy().setTextStyle(start, end, textStyle).build());
  range.setRichTextValues(richTextValues);
}
  • In this script, the values of cells "A10:A15" in the sheet of sheetName are used as textsForStrikethrough.

Note:

  • Unfortunately, I cannot understand about your actual situation. So when above script cannot be used for your actual situation, can you provide your sample Spreadsheet for replicating the issue? By this, I would like to confirm it.
Sign up to request clarification or add additional context in comments.

8 Comments

This is perfect! Only other request I have, is how would we modify it to where it is referencing a series of other cells to lookup the names? The list of names changes daily, so looking to have all inputs be able to update by a simple change of the names on the sheet rather than modifying the code. So say the names could be input in cell A10:A15. Pulling that list of names and updating the "textsForStrikethrough" logic.
@Michael Harris Thank you for replying. I'm glad your issue was resolved. About your 2nd question, I added one more sample script as an answer. Could you please confirm it? If I misunderstood your 2nd question, I apologize.
Thank you for your response again. Unfortunately it still was not working. Here is a sample sheet along with the sample code provided (updated with proper fields). I am getting an "illegal action" error on it currenty. docs.google.com/spreadsheets/d/…
@Michael Harris Thank you for replying. I apologize for the inconvenience. When I saw your sample Spreadsheet, I noticed that the range of "A15:A20" has the empty cells. From your replying, I couldn't notice it. I apologize for this. I think that he reason of your current is is due to this. In that case, please modify const textsForStrikethrough = sheet.getRange("A10:A15").getValues().flat(); to const textsForStrikethrough = sheet.getRange("A15:A20").getValues().flat().filter(String);, and test it again.
Success!! Thank you SOOO much, I really appreciate all your help on this!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.