I have a radio button with a few options in my google Doc. When the user selects an option, it adds a section with a heading and also paragraph. It should add the section only if the section isn't available and append the 'updated' text to the paragraph.
If the section is already available, it should only append the updated text at the end of the text.
Issue: Actually the behavior is pretty strange:
Diagnoses
updated text, new range? true
Diagnoses
updated text, new range? false
Anamnese
updated text, new range? true
Diagnose
updated text, new range? true
Anamneseupdated text, new range? false
updated text, new range? trueupdated text, new range? false
function manageSection(selectedSection) {
section = selectedSection;
var range = doc.getNamedRanges().find(r => r.getName() == section);
if (!range) {
Logger.log('No named range. Installing a named range');
setNamedRange(section)
} else {
Logger.log('Named range found.');
getNamedRange(section)
}
}
// No namedRange found - Set new named range with name section.
function setNamedRange(section) {
goToLastLine();
// Append a section header
var s = body.appendParagraph(section);
s.setHeading(DocumentApp.ParagraphHeading.HEADING4);
// Append paragraph to section
var insert = body.appendParagraph('');
var rangeBuilder = doc.newRange();
rangeBuilder.addElement(insert);
var savedInsert = rangeBuilder.build()
var namedRange = doc.addNamedRange(section, savedInsert);
var namedRangeId = namedRange.getId();
// select the namedRange
doc.setSelection(doc.getNamedRangeById(namedRangeId).getRange());
var newRange = true;
changeTextByNamedRange(section, newRange)
}
// Existing namedRange found.
function getNamedRange(section) {
Logger.log('getNamedRange() started')
var newRange = false;
changeTextByNamedRange(section, newRange)
}
// Update named range.
function changeTextByNamedRange(section, newRange) {
docUi.alert('section:' + section);
var range = doc.getNamedRanges().find(r => r.getName() == section);
// test
var updateText = "updated text, new range? " + newRange;
//
range.getRange().getRangeElements().forEach(e => e.getElement().asText().appendText(updateText));
}
function goToLastLine(){
const kids = body.getNumChildren()
const lastKid = body.getChild(kids - 1)
let last = 0
try {
const lastPar = body.getChild(kids - 1).asParagraph()
last = doc.newPosition(lastPar.getChild(0), lastPar.getText().length)
} catch (e) {
last = doc.newPosition(body.getChild(kids - 1), 0)
} finally {
doc.setCursor(last)
}
}
I have a workaround working and feel free to modify if it still is within your goal.
I modified setNamedRange
and changeTextByNamedRange
functions. Here are their modifications:
function setNamedRange(section) {
// Append a section header
goToLastLine();
var s = body.appendParagraph(section);
s.setHeading(DocumentApp.ParagraphHeading.HEADING4);
// Append paragraph to section
// for some reason, it fails to include the 1st paragraph when it is blank
// you can add a space, or any character just to include the 1st one properly
var insert = body.appendParagraph("\t");
var rangeBuilder = doc.newRange();
rangeBuilder.addElement(insert);
var savedInsert = rangeBuilder.build();
var namedRange = doc.addNamedRange(section, savedInsert);
var namedRangeId = namedRange.getId();
// select the namedRange
doc.setSelection(doc.getNamedRangeById(namedRangeId).getRange());
changeTextByNamedRange(section);
}
function changeTextByNamedRange(section) {
// docUi.alert('section:' + section);
var range = doc.getNamedRanges().find(r => r.getName() == section);
// get list of section names
var sectionNames = doc.getNamedRanges().map(r => r.getName());
var updateText = "Newer Text is appended for this section " + section + ". ";
// this section contains the succeeding sections as well
// so you have to end the loop when you encounter another section
// use some instead of forEach to be able to break the loop.
range.getRange().getRangeElements().some(e => {
var element = e.getElement();
// do anything you want. Note that this will loop to each element of that range.
// if section has multiple elements, it will append to each element.
// since we are only appending text to a single paragraph element, this currently works
element.asText().appendText(updateText)
// end loop when you encounter a text that is one of the section names
return !sectionNames.includes(element.asText())
});
}
manageSection
again. This is the result.