Problems with body.findText in Google apps script - google-apps-script

I have a Google doc which was created in Word and imported. I want to locate a 'marker' in the text so that I can insert a table at that point. However, I am unable to progress because my script keeps falling over at the "findText()" point. I have looked at a number of answers to similar problems on here and used what I think are identical methods, but it still falls over!
Rather than post code here, it seems clearer to post a screenshot of exactly what I get when I attempt to run the script. The first two items in the execution log prove that a) the document is being opened correctly and b) that the body is being correctly identified. There is definitely a "$" sign later in the text, so why am I getting the error?
Script
var doc = DocumentApp.openByUrl("https://docs.google.com/document/d/###/edit");
var body = doc.getBody();
var tblLoc = body.findText("$");
console.log(tblLoc)

Modification points:
From your following image,
I thought that the reason of your issue is due to $ of body.findText("$").
In this case, I think that it is required add \\ like body.findText("\\$")
The method of findText() returns the object of DocumentApp.RangeElement. So when you use console.log(tblLoc) and when the value is retrieved, {} is shown in the log.
When you want to see the retrieved value, for example, you can use console.log(tblLoc.getElement().asText().getText()).
When above points are reflected to your script, it becomes as follows.
Modified script:
const doc = DocumentApp.openByUrl("https://docs.google.com/document/d/###/edit");
const body = doc.getBody();
const tblLoc = body.findText("\\$");
console.log(tblLoc.getElement().asText().getText())
Reference:
findText(searchPattern)

Related

How to I save text from a document into a variable?

I want to take the text for a document and save it as a variable. I looked in the documentation and found "getText" something I think shall work. https://developers.google.com/apps-script/reference/document/footnote-section#gettext
I just get a problem when I try using it, because it's not a pre built function it gives the error massage "TypeError: Cannot read property 'getText' of null". So I looked at some more into it and noticed I needed Authorization:
"Scripts that use this method require authorization with one or more of the following scopes:
https://www.googleapis.com/auth/documents.currentonly
https://www.googleapis.com/auth/documents"
So how do I get the required authorization, do I need to do something different or is there another way i could do it?
It's just going to run on some of my docs for fun to se what funny things I am able to do with the program.
(New to programing, now the basics but just trying to see if programing is something for me)
Thanks in advance
Given with this sample document
You can start with this sample code below.
Code:
function myFunction() {
var body = DocumentApp.getActiveDocument().getBody();
var text = body.editAsText();
Logger.log(text.getText()); // returns all text in document ("Hey, search for me!!! I am <here>!!")
// 1. Regular expression (exec)
var regExp = new RegExp("<\(.*\)>", "gi"); // "i" is for case insensitive
var search = regExp.exec(text.getText())[1];
Logger.log(search); // returns "here"
// 2. (search)
Logger.log(text.getText().search(/here/)); // returns the index where the string was found, or -1 if not found
}
Output:
Note:
getText will return the text of the Class Text.
If you want to get a specific pattern from the document, you need to use Regular expression. I prefer the exec method. See usage for more details
For the authorization, you only need to click allow. I assume you are using apps script due to the tag.

Apps script JSON.parse() returns unexpected result, how can I solve this?

I am currently working on external app using Google Sheets and JSON for data transmission via Fetch API. I decided to mock the scenario (for debugging matters) then simple JSON comes from my external app through prepared Code.gs to be posted on Google sheets. The code snippet I run through Apps-scripts looks like this:
function _doPost(/* e */) {
// const body = e.postData.contents;
const bodyJSON = JSON.parse("{\"coords\" : \"123,456,789,112,113,114,115,116\"}" /* instead of : body */);
const db = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
db.getRange("A1:A10").setValue(bodyJSON.coords).setNumberFormat("#"); // get range, set value, set text format
}
The problem is the result I get: 123,456,789,112,113,000,000,000 As you see, starting from 114 and the later it outputs me 000,... instead. I thought, okay I am gonna explicitly specify format to be returned (saved) as a text format. If the output within the range selected on Google Sheets UI : Format -> Number -> it shows me Text.
However, interesting magic happens, let's say if I would update the body of the JSON to be parsed something like that when the sequence of numbers composed of 2 digits instead of 3 (notice: those are actual part of string, not true numbers, separated by comma!) : "{\"coords\" : \"123,456,789,112,113,114,115,116,17,18\"}" it would not only show response result as expected but also brings back id est fixes the "corrupted" values hidden under the 000,... as so : "{"coords" : "123,456,789,112,113,114,115,116,17,18 "}".
Even Logger.log() returns me initial JSON input as expected. I really have no clue what is going on. I would really appreciate one's correspondence to help solving this issue. Thank you.
You can try directly assigning a JSON formatted string in your bodyJSON variable instead of parsing a set of string using JSON.parse.
Part of your code should look like this:
const bodyJSON = {
"coords" : "123,456,789,112,113,114,115,116"
}
I found simple workaround after all: just added the preceding pair of zeros 0,0,123,... at the very beginning of coords. This prevents so called culprit I defined in my issue. If anyone interested, the external app I am building currently, it's called Hotspot widget : play around with DOM, append a marker which coordinates (coords) being pushed through Apps-script and saved to Google Sheets. I am providing a link with instructions on how to set up one's own copy of the app. It's a decent start-off for learning Vanilla JavaScript basics including simple database approach on the fly. Thank you and good luck!
Hotspot widget on Github

How to get validation pattern from Google Form item

In Google Forms, a question/item of class TextItem can have a validation pattern set (i.e., the response must match the pattern to be accepted by the form) by doing something like:
var textValidation = FormApp.createTextValidation()
.requireTextMatchesPattern(my_regex_pattern)
.build();
textItem.setValidation(textValidation);
I would like to read that pattern from an existing textItem (in order to have a script go through several questions with unique patterns and save them), but I cannot find any references to relevant methods or properties for validation rules, e.g. (made-up examples):
var existing_pattern = textItem.getTextMatchesPattern();
or
var existing_patern = textItem.getValidation.getTextMatchesPattern();
From what I can see, it looks like this is not actually possible, but that seems quite strange. Am I missing something?
Note: Using the Web interface, it's trivial to get the pattern for a given question/item. I'm specifically asking how to get it through a script.

File removeEditor issue (DriveApp)

I have an issue trying to remove active user editor from a file.
When I try the follwing code it works just fine :
function testOwner() {
var theFile = DriveApp.createFile('New Text File', 'Hello, world!');
theFile.setOwner('anemail#mydomain.fr');
theFile.removeEditor(Session.getActiveUser().getEmail());
}
But when I'm using the 'makeCopy' method I get a message error that stops the script even if the editor has been removed. Here is the code :
function testOwner2() {
var template = DriveApp.getFileById(TEMPLATE_ID);
var theFile = template.makeCopy('Name');
theFile.setOwner('anemail#mydomain.fr');
theFile.removeEditor(Session.getActiveUser().getEmail());
}
The error message on the removeEditor line : 'Impossible de trouver l'élément correspondant à cet identifiant. Vous n'êtes peut-être pas autorisé à y accéder.' meaning 'Couldn't find any element matching this ID. Maybe you are not authorized to access it'
I didn't find any question on this. Is is a known issue ?
Thanks for your help !
when you .makeCopy(), all the editors get removed for the new file.
in addition to help debug, use Logger some and view the logs...
function testOwner2() {
var template = DriveApp.getFileById(TEMPLATE_ID);
var theFile = template.makeCopy('Name');
theFile.setOwner('anemail#mydomain.fr');
var editors = theFile.getEditors();
for ( var i in editors ) { Logger.log(editors[i].getEmail()); }
Logger.log(Session.getActiveUser().getEmail());
theFile.removeEditor(Session.getActiveUser().getEmail());
}
Try .getEffectiveUser() instead of .getActiveUser() as that's typically a cause of unexpected results as well.
This is to be considered as a comment, just taking a bit more place than a regular one.
There seems to be an issue with the code suggested in the other answer : You just can't remove yourself as an editor (and you automatically become an editor when you set the ownership to another user) when you are not the owner of the copied file anymore... you will get just the same error message.
The first code snippet you give that creates a file should follow the same logic but - as I learned today (thanks for that) - it does not and I really don't know why.
( I hope someone "better informed" will explain... )
I guess the only solution (at least that I can imagine using a script) if you don't want to be an editor of the copy would be to integrate a small script in your template (that would be copied in the copy) to create a menu allowing the new user to call a function that would remove you as an editor.
Or more simply after all, explain how to do it from the Drive Ui itself ;-)

Understanding google spreadsheets set vs get logic

I'm desperately trying to learn to "think" in this language (my native coding language is VBA/ASP).
Here is a very basic example that simply reads the contents of a specific cell in Sheet1 and then assigns that value to a variable named rngVal
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Sheet1"));
var rngVal = ss.setActiveSelection("A1").getValues();
When I attempt to deconstruct this very simple 3-line piece of code (in the interest of understanding it's purpose), I admit to being rather perplexed.
Here's why:
When I insert a msgbox after each line, I get this:
var ss = SpreadsheetApp.getActiveSpreadsheet(); = "Spreadsheet"
ss.setActiveSheet(ss.getSheetByName("Sheet1")); = "Spreadsheet"
var rngVal = ss.setActiveSelection("A1").getValues(); = The cell value
What is "Spreadsheet"?
How is this helpful(?) and how can I use it for the benefit of navigating the worksheet and reading/writing values within it?
That's 2 lines of code that does what(?), and for what benefit?
(I'm not trying to be combative, I'm just trying to understand so that I can learn to "think" in this language)
Secondly:
In the first line, what am I get ting?
In the second line I'm first set 'ting, and then I'm get 'ting? (I'm very confused about what that line is actually doing)
In the third (last) line there is more set 'ting and get 'ting, although this time it's not nested.
This is very basic code (functionally), but I'm having trouble grasping it's logic in terms of how to "think" using that logic.
Is there anyone out there who would be kind enough to show some patience and help me by describing the step by step logic of this simple code of selecting a cell, capturing it's value, and then assigning it to a variable?
Please understand, that when I "think" of how to do that very simple task, I can do it in one very concise line (in VBA)...
rngVal = Sheets("Sheet1").Range("A1").Value
...therefore I am really confused by all of the "Spreadsheet" stuff and the need for 3 lines filled with set's and get's.
Anyone? Please?
Hmm somehow the correct answer (my other one) got voted down. Again its pointless to do setactiveselection, there is no need to change the selected cell it just makes your code slower.
Google uses Javascript Classes to represent these different Objects.
I've split line 3 into two parts to help with my explanation. Please compare:
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Sheet1"));
var rng = ss.setActiveSelection("A1");
var val = rng.getValues();
Each line above returns a different class of Object. The first line returns an Object with class Spreadsheet, the second line returns an object of class Sheet, the third line returns an object of class Range, and the final line returns an object of class Object.
Take a look here for documentation on the various actions (methods) that can be performed on/with the different classes of objects. When I'm building a Google App, I live on that webpage.
To compare the above with the code you understand from VBA, this line:
rngVal = Sheets("Sheet1").Range("A1").Value
Could be written in Javascript in one line as follows:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").setActiveSelection("A1").getValues();
Hope that helps. Let me know if you have questions.
You guys are doing it more complex than neeeded. No need to mess with selection.
Getactivespreadsheet ().getsheetbyname ("x").getrange ("a1").getValue () also works.