How to reference an external spreadsheet with Google Apps Scripts - google-apps-script

Update: It worked for 5 minutes then stopped working again. Not exactly sure why it's only working part of the time?
This sounds like it's supposed to be simple but I'm only finding information on "getActive" and my function works if I'm using all internal sheets but I tried using openById and nothing happened and openByUrl returns an error. The following is a simplified example of what I'm trying to do:
var store_data_sheet = SpreadsheetApp.openByID('ID here..').getSheetByName('Data');
store_data_sheet.getRange('A1').setValue('testing')
store_data_sheet.insertRows(1);
I'm sure I'm just using the wrong keywords or maybe this isn't even allowed but multiple users will be using their own copy of a specific sheet that runs this function and I'd just like to take certain cell's data and copy it to one external sheet (which is why it also inserts a row so it can push down entries)
Maybe I'm using the wrong "ID"? I assumed the number inside the URL was the ID. If it's something more specific, please let me know.
Like I said, this works flawlessly if I'm referencing an internal sheet. I'd like to be able to do the same exact thing with an external spreadsheet if possible. Thank you!

I found the issue. This function also renames the sheet file so if there is anything in the cell that is used to rename the file, it won't run the storing functions. I either need to run these before the renaming or take out the renaming aspect. ---moving these before the renaming part fixed the problem.

Related

Why won't my macro correctly copy/paste values only after the first instance?

Updated everything to include the ultimate goal of this spreadsheet and the issue I encountered during early testing so that if there's a better way to do this that someone with experience can identify, I can change my approach and do that instead.
Link to copy of sheet here
The Issue:
This macro uses paste special (values only) twice, but it only correctly pastes the first one and does nothing for the second. For example, the the first instance copies data from C6 and pastes only the value to F6, which it does. The second copies from K6 and pastes only the value to M6, which it does not do. Everything else is functioning correctly except for this.
For context, this macro also copies a formula down in between the two copy/paste actions. You'll see the code for that below as well. It's working as intended, so you can ignore that.
With help from below, we identified the issue was that the second paste values only function wasn't working because it was copying the cell before that cell could finish summing its formula.
For example, let's say K6 was =sum(K4+K5) with K4=1 and k5=4. Before the sum could record the answer, "5" in that cell, the copy was grabbing the empty data and pasting it, thus pasting nothing.
I tried setting up a delay using sleep, but it was not a consistent solution. It only works about 50% of the time. If it's possible to set up a delay based around letting a formula finishing its output, that would be a perfect solution. If anyone has experience with a similar issue or suggestions for optimization threads, please link below. I'll loop back if I find a solution.
The Goal and Backstory:
This is a mock-up of an internal tracker we use to gauge our availability (mins) against the project (in mins) to determine roughly when we have the project complete. We use this tracker to determine if something will be late, if we have the availability from our team to take on more projects, etc. It's all manual, and we don't have anyone particularly strong with scripts.
Right now, our solution is to manually enter in our availability in each cell with the assistance of basic sum formulas. This takes a lot of time and is prone to human error. So, I'm trying to find a macro that will do the math for us with my very limited experience in scripts/macros.
In the "The Ideal" tab, I've manually created an example of what I'm ultimately working towards -- a macro that sums and enters in data based on availability vs. project mins. I'm obviously new to this, so there are inevitably inefficiencies and I may be completely on the wrong track. If so, please tell me and offer me an explanation as if you were speaking to a grandparent with basic computer knowledge.
Thanks everyone for your help!
Here's the code:
function TestCalc1() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('D5:H5').activate();
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('D5:H6'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
spreadsheet.getRange('I6').activate();
spreadsheet.getRange('H6').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getRange('H6').activate();
};
Try this,
function TestCalc1() {
var spreadsheet = SpreadsheetApp.getActive();
var cellsD5H5 = spreadsheet.getRange("D5:H5").getValues();
spreadsheet.getRange("D6:H6").setValues(cellsD5H5);
var cellH6 = spreadsheet.getRange("H6").getValues();
spreadsheet.getRange("I6").setValues(cellH6);
//spreadsheet.getRange("H6").activate();
};
getValues() -
https://developers.google.com/apps-script/reference/spreadsheet/range#getValues()

Refresh Button / Auto Update GOOGLE SPREADSHEET

I hope you can help me. I have been trying to get this working for quite some time.
I am taking the API from a website import it into google spreadsheets VIA importjson()
ImportJSON("http://api.796.com/v3/futures/ticker.html?type=weekly")
https://gist.github.com/chrislkeller/5719258
I have no problem importing the json data into google spreadsheet, now the hard part is making the data update, I would really like it to auto update but even a "update now" button would be great.
Thanks,
This has been driving me nuts.
BV
So I was searching for a good way to do this as well. Here is what I have found so far.
If you change the function line of the importJSON like this:
function ImportJSON(url, query, parseOptions, recalc) {
}
Which just adds the recalc parameter to the function definition. This is a 'trick' because that parameter is not used for anything other than to make GSheet think something has changed.
Then in the call to ImportJSON (in a GSheet cell), you add in the function call like this:
=ImportJSON("https://yourDomain.com/something","","rawHeaders",A1)
Then in the sheet you can manually change the value of A1 to anything different than it is. The Sheet and all the imports will get refreshed.
Another ... non-technical trick ... manually change A1 to 1 then 2 then 3. Each time the sheet will recalc. Now you can use the UNDO and REDO buttons to change the numbers and recalc the sheet.
A little of a kludge Hack, but it does make for a one-button "recalc" of a sort.
You can just add the time trigger
https://developers.google.com/apps-script/understanding_triggers
File > Spreadsheet settings > Calculation > Recalculation: On change and every minute
Then you can insert a =now() column and it will refresh the sheet every minute.
Apologies if you've tried this already, I have it setup now in a sheet but am waiting for a live event to test, so it might not even work.
Im not really a javascript person, but I might have a little code that might help start you off. (Sorry if it does not help). What I use in my site is this (I changed it a little bit to incorporate your url).
$( document ).ready(function($) {
setInterval(function(){
$('.sell').load('http://api.796.com/v3/futures/ticker.html?type=weekly');
}, 5000);
});
This just grabs the JSON every 5 seconds, so be sure you parse the JSON and display the data you need. Hope this helps! :)

Checking if a file has been edited

I want to know if there is a way to check if a file has been edited. I looked for methods that can make it for me on Google Apps library, but I have found nothing about it. I don't know if I searched wrong.
Basically, I need to take a file, take a measurable data (something like size) of this file and store on a variable. Then, I need to take that measurable data again, store on another variable, and compare if there was a change. I need a boolean return.
Anyone?
You could do the following (pseudo with links to documentation):
Get the file you want to check using the DocList Class.
Get the ID of that File once you have it using File.getID()
Get the last edit timestamp using File.getLastUpdated()
Store this value in a Spreadsheet, or maybe Script or User Properties.
When you want to check to see if the File was updated, simply File.getFileById()
Repeat step 3.
Then compare the two last-edited timestamps with an operator like !=, or do more complex comparisons on the Dates if you want.
Depending on the result of step 7, return true or false.
Google's documentation is great, for all their services. You just need to read it a bit to understand what kind of power you have through scripting. Hopefully my pseudo-method helps in solving your problem!
Look at the file update date: https://developers.google.com/apps-script/reference/drive/file#getLastUpdated() and for storing data look up the storing data section in the apps script help page.
You could also use the GAT General Audit Tool http://goo.gl/hzZ2yf... which reports when files were edited , viewed and much more.

Organizing Spreadsheet Code in several *.gs files - even possible?

I am trying to organize my code for a Spreadsheet in several script files. Within the script editor I can create as many *.gs files as I want, but I can't figure out how to access code that would be defined in another script.
Simple Example of what I'd like do achieve:
Code.gs:
function onEdit(){
myFunctionFromLibrary_gs();
}
Library.gs:
function myFunctionFromLibrary_gs(){
Browser.msgBox("hi there");
}
The onEdit() is obviously called by a Trigger.
Without modification this will result in a Runtime-Error, stating that
myFunctionFromLibrary_gs TypeError: is not a function, it is undefined.
So how can I make this work, or is this currently not supported?
Thx in advance for your help.
Yes, it's possible.
You are not limited to a single server Code.gs file. You can spread server code across multiple files for ease of development. All of the server files are loaded into the same global namespace, so use JavaScript classes when you want to provide safe encapsulation.
Reference: Google Documentation - features and limitations
I don't know what the _gs suffix means for Google, but without it (see code bellow), the code works.
file1.gs:
function onEdit(){
myFunctionFromLibrary();
}
file2.gs
function myFunctionFromLibrary(){
Browser.msgBox("hi there");
}
I know this is an old question but I found it looking for a similar task and happened to find the answer during my same search.
From the docs at https://developers.google.com/apps-script/guide_libraries#writingLibrary:
If you want one or more methods of your script to not be visible (nor usable) to your library users, you can end the name of the method with an underscore. For example, myPrivateMethod_().
While your function does not END in an underscore, it may have special meaning in other places than just this, or the _gs suffix may also have special meaning (particularly given the same filename suffix).

Google script DocsList service query string not working

I'm making a little script to automatically organize some autogenerated spreadsheets. The goal is to archive the spreadsheets in a directory based on their name (all of them start with the same name but end in a pattern I'm using to organize them). The problem I have is with the function:
lstFile = DocsList.find('type:spreadsheet title:"PROG_GRAL_CENTRE"');
The function doesn't have the query options specified in the docs, but I'm using it on another script and is working fine! I've also tried putting only:
lstFile = DocsList.find('PROG_GRAL_CENTRE');
which should find 200 documents, but none is found! Actually, if I type PROG_GRAL_CENTRE into the search box of my google Drive, all the documents are found, so I don't know what's wrong with my search filter.
Any thoughts?
The method find(query) looks for a string in file content, not only on file name... so even it it worked normally (meaning without the issue you mentioned) I'm not sure it would be a good solution for your use case since there would be a risk that some filename could be found inside another doc with another name (as a reference for example...).
Why don't you try getting all filenames in an array and search into this array instead ?
This can be done very easily and would bring an elegant solution to your problem wouldn't it ?
I'm working on this very same type of script right now ;-) here is the part that gets my files (just an example if ever you are interested):
var doclist=DocsList.getRootFolder().getFilesByType("document",0,2000);
var names = new Array();
for (nn=0;nn<doclist.length;++nn){
if(doclist[nn].getName().match("IMPRESSION_")=="IMPRESSION_"){
names.push([doclist[nn].getName(),doclist[nn].getId()]);
}
}
after that I sort the array the way I want and show the result in a list UI.