0

NB google DOCS not google sheets.

In the following code, I believe I'm doing the following:

  1. Insert two text elements ('0' and '1') then encapsulate them in two namedRanges tagged respectively with the names '0' and '1'. i.e. two namedRanges each with one text element only.
  2. Insert a new text element that is not part of any namedRange.
  3. Retrieve the text of the two named ranges.

The end result in the document is (correctly): 'new 1 0'.

However, when I print out the contents of the debug array, I get: enter image description here

As I understand it, I can use namedRanges to encapsulate/protect text elements so that I can retrieve them and manipulate them as I want (use setText() for example, or remove()) without them being affected by or affecting any other elements in the document. That seems to be the purpose of namedRanges.

Instead of getting a namedRange '0' with one text element '0' and a namedRange '1' with one text element '1', I end up with namedRange '0' having three elements (the one I want, the text element from namedRange '1' and the independent text element 'new') and namedRange '1' having two elements (the one I want and the independent text element 'new').

What have I done wrong?

testNamedRanges.gs:

function onOpen(e) {
  DocumentApp.getUi().createAddonMenu()
      .addItem('Test Named Ranges', 'showSidebar')
      .addToUi();
}
function onInstall(e) {
  onOpen(e);
}
function showSidebar() {
  var ui = HtmlService.createHtmlOutputFromFile('sidebar')
      .setTitle('Test namedRange');
  DocumentApp.getUi().showSidebar(ui);
}
function testNamedRange() {
var i, j, k, element, ranges, rangeNew, rangeElements, rangeBuilder;
var message = false;
var document = DocumentApp.getActiveDocument();
var cursor = document.getCursor();
var debug = [];

// Remove any pre-existing named ranges
  ranges = document.getNamedRanges();
  for (j = 0; j < ranges.length; j++) {
    ranges[j].remove();
  }
// Create and insert two new named ranges each with a single text element
  for (i = 0; i < 2; i++) {
    element = cursor.insertText(i + ' ');
    rangeBuilder = document.newRange();
    rangeBuilder.addElement(element);
    document.addNamedRange(i, rangeBuilder.build());
  }
// Insert independent text element
  cursor.insertText('new ');
// Get the named ranges and their text elements and place in the debug array
  for (i = 0; i < 2; i++) {
    ranges = document.getNamedRanges(i);
    for (j = 0; j < ranges.length; j++) {
      rangeElements = ranges[j].getRange().getRangeElements();
      for (k = 0; k < rangeElements.length; k++) {
        debug.push(['tag: ' + i, 'element: ' + k, 'text: ' + rangeElements[k].getElement().getText()]);
      }
    }
  }
// return debug array to sidebar
  return {
    debug: debug
  };
}
sidebar.html:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <button class="button" id="testNamedRanges" alt="testNamedRanges" title="testNamedRanges">testNamedRanges</button>
  <script>
    document.getElementById("testNamedRanges").onclick = testNamedRanges;

function testNamedRanges() {
    google.script.run
    .withSuccessHandler(testNamedRangeResult)
    .testNamedRange();
  }
  function testNamedRangeResult(result) {
    for (var i = 0; i < result.debug.length; i++) {
      console.table(result.debug[i]);
    }
    return;
  }
  </script>
  </body>
</html>

Image showing previous attempts to use named ranges are still stored in the document source: enter image description here

In attempting to get rid of previous named ranges, I inserted this in the script above just before I create the two new named ranges:

  ranges = document.getNamedRanges();
  for (j = 0; j < ranges.length; j++) {
    ranges[j].remove();
  }

This appears to have had no effect: the previous named ranges are still in the document's source in a script element and I still get the erroneous debug array data.

  • Can you share a copy of the document and how are you doing it to reproduce the issue? – Kessy Mar 17 '21 at 11:16
  • @Kessy thanks for the response. If by document you mean the google docs it's blank on the screen until I run the code at which point I get 'new 1 0'. Looking at the source, I notice there is a large – Mark Grimshaw-Aagaard Mar 18 '21 at 10:27
  • @Kessy I've now added the full MRE including sidebar.html and tested it on a new document (same erroroneous result). – Mark Grimshaw-Aagaard Mar 18 '21 at 11:49
  • This old post was passed onto me: https://stackoverflow.com/questions/30654389/how-to-add-named-ranges-to-sub-paragraph-elements-in-google-apps-script. The workaround there works but is far from ideal (if the images are deleted, the named ranges break down again). This appears to be a long-standing issue with google docs namedRanges that seems to pretty much invalidate their use. – Mark Grimshaw-Aagaard Mar 18 '21 at 16:01
  • do you mean that the issue is on the debug page of the chrome console, where the values should be all inside one array, instead they are on 3? – Kessy Mar 23 '21 at 16:48
  • @Kessy I explain further here: https://issuetracker.google.com/issues/183019121. From the documentation: "Named ranges allow developers to associate parts of a document with an arbitrary user-defined label so their contents can be programmatically read or edited at a later time." This isn't the case at all as the named range expands beyond the developer's control to include other text elements that were never intended to be part of the range. This makes it impossible to programmatically read or edit the contents at a later time. – Mark Grimshaw-Aagaard Mar 25 '21 at 05:58
  • Could you check the partial elements explained on the link you posted from issue tracker. Did it help you? – Kessy Apr 02 '21 at 14:43
  • @Kessy Unfortunately not. Using the methods from Doc, the named range start and end points don't change regardless of any other text or named ranges inserted on the same line. The issue is that an existing named range swallows up other text elements (partial or not) that were never intended to be part of that range. This makes namedRanges (in google docs) unusable as per their documentation. – Mark Grimshaw-Aagaard Apr 04 '21 at 08:22
  • I have thought of something that might help. Have you considered splitting the part when the element is created and the part where the named range is created? It would work also by having already the 1 and 0 on the doc, and creating a named range of each one. – Kessy Apr 08 '21 at 15:54

0 Answers0