Home > Net >  Canonical way to reference Elements
Canonical way to reference Elements

Time:02-26

Is there a canonical way to set an ID—or other searchable, persistent data attribute—on Elements in Google Docs, such that I can easily refer back to it later? I'm looking for something equivalent to getElementById in javascript. Almost all examples I've seen, including Google's own docs, seem to reference objects by searching for text strings or inserting new strings.

I've found one reference in the NamedRanges class to a getId function, but I can't find any place to set that ID. I do see the setAttributes function on Elements but that seems to apply only for pre-defined attribute types. I haven't tested that, though.

In case it's relevant: my interest is in automatically creating a document from a Google Sheet and populating based on the current values in the sheet. I'd like to assign specific Elements individual IDs so I can easily retrieve the Element and replace the text if the values in the sheet change later on.

CodePudding user response:

So I been checking the documentation about elements for Google Docs in AppScript and it seems that some of them can be modified but not as freely as it looks as noted in the documentation:

Elements shown in bold can be inserted; non-bold elements can only be manipulated in place.

I tried checking with setAttributes as you mentioned however the attributes itself can only be from a document elements like: TEXT, PARAGRAPH, TABLE, ETC, this elements can't receive an ID as there is not method to insert an specific ID as you are requiring, most of the values that can be inserted are specific element attributes like: Font size, Font family, etc.

CodePudding user response:

Turns out that this is possible using NamedRanges, I just didn't read carefully enough.

Note: All the following examples are working off this Google doc. You can make a copy and select "Script Editor" from the Tools menu to see the code.

You can assign named ranges pretty easily using Apps Script. The below code looks through the doc for [[TITLE]] and [[ABSTRACT]] and assigns named ranges to those chunks. Note that in the aforelinked doc I put them in a table to avoid issues with partial ranges.

function assignNamedRanges() {
  const doc = DocumentApp.getActiveDocument();
  const body = doc.getBody();
  
  const placeholders = ["title", "abstract"];

  placeholders.forEach(p => {
    const rangeBuilder = doc.newRange();
    const text = body.findText("[["   p.toUpperCase()   "]]");
    rangeBuilder.addElement(text.getElement());
    doc.addNamedRange(p, rangeBuilder.build());
  });
}

Once you assigned them, you can update the range to something else in a separate function:

function updateNamedRanges() {
  const doc = DocumentApp.getActiveDocument();
  const body = doc.getBody();

  const title = doc.getNamedRanges("title")[0];
  const abstract = doc.getNamedRanges("abstract")[0];

  title.getRange().getRangeElements()[0].getElement().asText().setText("Bob");
  abstract.getRange().getRangeElements()[0].getElement().asText().setText("I like pancakes");
}

Note that NamedRanges are persistent, and the multiple NamedRange instances can have the same name. This means that if you run the first function four times, you'll have eight named ranges. You can make a convenience function to clear all those out pretty easily:

function clearNamedRanges() {
  DocumentApp.getActiveDocument().getNamedRanges().forEach(r => {
    r.remove();
  })
}
  • Related