Find id of element on already made google form? - google-apps-script

I have a form made on google docs, and I have a script that I've just created (that isn't complete) that will analyze the responses on the form, and validate them based on info from a different google doc. Through trial and error I have figured out the id's for all of the elements on said form. I used:
var body = ""
var bodyTitle = ""
for (var i = 1; i < its.length; i ++)
{
body = body + " " +its[i].getId()
bodyTitle = bodyTitle + " " + its[i].getTitle()
}
and then by logging that out and basically just counting, the 5th id matches the 5th title, I have all of the id's. I'm just wondering for next time, is there a way I can look at the form and find it'd ID without doing this?
With HTML forms (I use chrome fyi) you can right click, inspect element, and you can see the id for page elements, and refer to them by that id in javascript. Is there a way to do this in Google Forms? that way I don't have to screw with just logging out all the id's and titles and matching them up.
Keep in mind: these are all forms created in Google Forms by users, they insist on making them. None of them are code made so I haven't been able to code the id's myself.

Something like this will show you the ids in the logger... Open the form edit menu, load the script editor, paste the below inside a function and run it.
var form = FormApp.getActiveForm();
var items = form.getItems();
for (var i in items) {
Logger.log(items[i].getTitle() + ': ' + items[i].getId());
}
To see the IDs manually in Chrome >> View Form >> right-click on the question Label >> Inspect element >> look for the for="entry_XXXXXXX" attribute. That 'xxxxxxx' will be the id.

2021 update:
To find the ID manually:
Inspect question element
Find [data-params] attribute
The second number will be the right one
Example:
data-params="%.#.[860146445,"Question",null,0,[[305915825,[],true,[],[],null,null,null,null,null,[null,[]]]],null,null,null,[]],"i1","i2","i3",false]"
305915825 - this is the field ID that you can use like ?entry.305915825=<your-predefined-content>

An update to Bryan P's answer:
To find the ID:
view the form (as if you were taking it)
right click and inspect the question name
look for either:
data-item-id="##########", or
aria-describedby="i.desc.########## i3"
You want the ##########.

Related

Is there a way to add a list item to a specific place in google docs?

I have a script that creates a copy of a google doc when a form is submitted, and has find and replace functionality based on the form submitted. Currently I have a list of items from a checklist that I find and replace but I'd like to shift it to append so I don't end up with excess items in a list left without being replaced.
Currently when script is run it'll fill in what can be filled:
Processes to work
example process 1 from google form
example process 2 from google form
{{process3}}
{{process4}}
{{process5}}
I'd like if possible, to be able to avoid find and replace and be able to append to this list instead. My issue is that this list is in a specific location and I'd like to call to the index of it and then append at that point. I'm fairly new to writing any kind of code.
Here is the example how you can append a new item at the end of existed list in your document:
function append_item_at_the_end_of_a_list() {
var body = DocumentApp.getActiveDocument().getBody();
var list = body.getListItems().pop(); // get the last list item
var index = body.getChildIndex(list)+1; // get index of the item
body.insertListItem(index, 'New list item'); // append a new list item at the end
}
The code supposes that the document has just one list or the wanted list is a last one. If you have several lists and the modified list is not the last one it needs a more complicated solution.

Can I add Heading text to the footer in a Google Docs file automatically?

I have a document that consists of approximately 20 chapters, divided over 60 pages. Each new chapter starts at the top of a new page. What I would like to do, is to automatically add the active Chapter title to the footer of that page. I know this behavior is possible in Microsoft Word, but I can not find it in Google Docs.
It can be done manually by inserting section breaks, but that is inconvenient for me, since I want to use this process in over 1.000 different documents.
Example:
Chapter 1 is called "Test chapter" and starts at page 1
Chapter 2 is called "Another chapter" and starts at page 4
Then on page 1, 2 and 3 the footer of the page should contain the text "Test Chapter". On page 4, the footer should contain the text "Another chapter".
Thank you in advance!
Unfortunately, this still isn't available as of the moment and has no update since the issue of the bug.
I have been trying to circumvent this issue via Apps Script and never had a proper solution as the footers and headers are being treated as one.
By default, changing a footer section will apply to all footer sections, and if they were separated by section break, they are not ordered by page but by the order of them being added on the document so it would be tricky and would require you to add them in this order for my code to work.
Object Order:
After BODY_SECTION, next children of the document should be alternating HEADER_SECTION then FOOTER_SECTION.
NOTE:
Logger.log part of the code shows what is the object order of your document. If it looks like the above order, then the code below will work.
Code:
function setHeaderAsFooter() {
var d = DocumentApp.getActiveDocument();
var p = d.getBody().getParent();
for ( var i = 0; i < p.getNumChildren(); i += 1 ) {
var c = p.getChild(i);
var t = c.getType();
// Check what type is the object
// Comment out if-block below to see if what is the object order in your document
Logger.log(t);
// Every header you encounter, set it as footer value of the next object
if ( t === DocumentApp.ElementType.HEADER_SECTION) {
var f = c.getNextSibling();
f.asFooterSection().setText(c.asHeaderSection().getText());
}
}
}
If they aren't in HEADER -> FOOTER alternating order after the BODY, then the code above won't work.
Most likely, this is not the answer you were hoping for, so I do sincerely apologize. I hope that this answer will help you in any way at least.

How to copy and paste specific information in a same doc using Google App Script?

I'm very new using GAS what I'm trying to do is to copy some information that is already on the bottom of my doc to anywhere I want in my docs, this should work just by copying the information and paste it at the place I desire, but I want it to be done with Google App Script because it's a daily task and it's easier to do it with a function, instead of copying and pasting manually. Searching on how to do this, I found a lot of information about how to do it on Spreadsheets, but I needed it to be done on Google Docs. How can I do that?
If someone can guide me or send me a link to another similar question that would be very helpful, I don't know where to start.
This is what I have until now, I get all the data of the current doc and set it again to the page, the code gives me problems because it deletes my other information, also it selects all the doc's information. I want to select a piece of specific information and don't copy the content style.
function copyPasteInfo() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var notesText = body.getText();
body.appendPageBreak();
body.setText(notesText);
}
Link to the doc document
https://docs.google.com/document/d/1s2TCspXbjvHVurwhIWSdwJ_hMcZIoLTKj4FAB82nmhM/edit
Video example of how what i want to do
https://www.screencast.com/t/UmEon8Fm0lPe
Picture of the information i'm trying to copy and paste to the bottom of my doc
If I correctly understood your question, this code will help you to achieve your goal.
let body = DocumentApp.getActiveDocument().getBody();
function moveTable() {
// Get the last table and the previous table found in your Doc
const [previousTable, bottomTable] = getDesireTables();
// Make a copy of your last table
const bottomTableCopy = bottomTable.copy();
// Get the previous table's index
const previousTableIndex = body.getChildIndex(previousTable);
// Insert the last table's copy under the previous table in your Doc
body.insertTable(previousTableIndex + 1, bottomTableCopy);
// Remove the original last table
body.removeChild(bottomTable);
}
function getDesireTables(){
const tablesArr = body.getTables().slice(-3);
// Get the parent element type to check if it's a cell
const parentELementType = tablesArr[tablesArr.length - 1].getParent().getType();
if(parentELementType === DocumentApp.ElementType.TABLE_CELL){
// If there's a table inside a table, return this
return tablesArr.slice(0, 2);
}
else{
return tablesArr.slice(-2);
}
}
What I did was to get the last two tables in the Doc, then I made a copy of the last one and with the index of the previous one, I inserted it under the previous one.
Edit
I noticed you had a table inside a table. therefore I added the getDesireTables function. Which it will check if your bottom table has a table inside.
Docs
These are the docs I used to help you:
getTables().
copy().
insertTable(childIndex, table).

How do I build a simple HTML form to construct a link from two form fields?

At work, one of the systems I use outputs voyage schedules. The URL for each voyage is constructed as the form address followed by ?voyageCode= followed by the voyage number, which is a two-letter route prefix and a three-digit voyage number.
Rather than use the standard form, which has a whole bunch of fields I never need to use, I want to build a simple page where I can just select the route and enter a voyage number.
In practical terms, I'm trying to build a form with the following:
A drop-down menu or set of radio buttons to select the two-letter route code;
A text field to enter the three-digit route code;
A button or link to combine those inputs into a link in the format [LINK]?voyageCode=[ROUTE CODE][VOYAGE NUMBER]
My HTML knowledge is pretty outdated, and I've never worked much with forms. Can anyone advise on how I can construct this?
Why don't you use a select tag for the dropdown and a classic input text for the route coude ?
Then for the link part, you should capture the click event on your button through onClick and then call a small function that'll basically do that :
function concatRouteCode(){
var select= document.getElementById("routeCodeLetters");
var routeCodeLetters = select.options[select.selectedIndex].value;
var routeCodeNumber = document.getElementById('routeCode').value;
return routeCodeLettres+routeCodeNumber;
}
If you really want to combine the codes into a single query parameter, you'll have to use Javascript to fetch the values of the two fields and change the location. You don't need Javascript if you put the values into separate parameters, as in ?routeCode=xx&voyageNumber=123. In that case you would just give the select element the attribute name=routeCode and the input field the attribute name=voyageNumber.
In case you want to go with the first approach, you'd have something like
document.getElementById("idOfSubmitButton").addEventListener("load", function() {
const routeCode = document.getElementById("idOfSelectElement").value;
const voyageNumber = document.getElementById("idOfInputField").value;
location.href = "base URL here" + "?voyageCode=" + routeCode + voyageNumber;
});

Get page selection including HTML?

I'm writing a Chrome Extension, and I was wondering if it was possible to get the selected text of a particular tab, including the underlying HTML? So if I select a link, it should also return the <a> tag.
I tried looking at the context menu event objects (yes, I'm using a context menu for this), and this is all that comes with the callback:
editable : false
menuItemId : 1
pageUrl : <the URL>
selectionText : <the selected text in plaintext formatting, not HTML>
It also returns a Tab object, but nothing in there was very useful, either.
So I'm kind of at a loss here. Is this even possible? If so, any ideas you might have would be great. Thanks! :)
Getting the selected text of a page is fairly easy, you can do something like
var text = window.getSelection().toString();
and you'll get a text representation of the currently selected text that you can pass from a content script to a background page or a popup.
Getting HTML content is a lot more difficult, mostly because the selection isn't always at a clean HTML boundary in the document (what if you only select a small part of a long link, or a few cells of a table for example). The most direct way to get all of the html associated with a selection is to reference commonAncestorContainer, which is a property on a selection range that corresponds with the deepest node which contains both the start and end of the selection. To get this, you'd do something like:
var selection = window.getSelection();
// Only works with a single range - add extra logic to
// iterate over more ranges if needed
var range = selection.getRangeAt(0);
var container = range.commonAncestorContainer;
var html = container.innerHTML
Of course, this will likely contain a lot of HTML that wasn't actually selected. It's possible that you could iterate through the children of the common ancestor and prune out anything that wasn't in the selection, but that's going to be a bit more involved and may not be necessary depending on what you're trying to do.
To show how to wrap this all up into an extension, I've written a short sample which you can reference:
http://github.com/kurrik/chrome-extensions/tree/master/contentscript-selection/
If you don't want all of the siblings, just the selected HTML, use range's other methods like .cloneContents() (to copy) or .extractContents() (to cut).
Here I use .cloneContents():
function getSelectedHTML() {
var range = window.getSelection().getRangeAt(0); // Get the selected range
var div = document.createElement("div");
div.appendChild(range.cloneContents()); // Get the document fragment from selected range
return div.innerHTML; // Return the actual HTML
}