I'm automating some processes within Google Apps Script.
I have created a few functions that are currently independent from each other.
However now, I want to regroup them so's they are triggered within the "master" function.
function master(){
// code that imports data from a form and organises it
runMeAfterMaster();
}
function runMeAfterMaster(){
// code that should run after master
}
Both are in the same script file, both work independently but I can't seem to just be able to "invoke" or call my other function within the master one.
Please Help!
I ran into a similar issue when my function names started with lower case letters.
the error I got was:
TypeError: randomNumber is not a function
my code:
/*
goal of the script is to highlight project rotators
*/
function HightlightProject()
{
// get random number
var randomNumber = randomNumber();
}
function randomNumber()
{
// get cell from certain spread sheet
var cell = SpreadsheetApp.getActiveSpreadsheet().getRange("fundation rotator!B7");
// random number
var number = Math.floor(Math.random() * 100);
// set random number
cell.setValue(number);
}
if I capitalize randomNumber to RandomNumber, the function names turn pink, and it works.
/*
goal of the script is to highlight project rotators
*/
function HightlightProject()
{
// get random number
var randomNumber = RandomNumber();
}
function RandomNumber()
{
// get cell from certain spread sheet
var cell = SpreadsheetApp.getActiveSpreadsheet().getRange("fundation rotator!B7");
// random number
var number = Math.floor(Math.random() * 100);
// set random number
cell.setValue(number);
}
What you wrote is ok runMeAfterMaster look to be invoked, I suppose your problem is elsewhere have you decorated your functions with Logger.log?
eg:
function master(){
// code that imports data from a form and organises it
Logger.log("I'm in master now");
runMeAfterMaster();
Logger.log("still in master but after calling runMeAfterMaster");
}
function runMeAfterMaster(){
Logger.log("I'm in runMeAfterMaster now");
// code that should run after master
Logger.log("getting out of runMeAfterMaster");
}
if you can't use Logger.log because the function is triggered automatically (and you can't have a look at the logs) yoo can replace it by your own loggin function that write everything in a spreadsheet:
function logit(message) {
SpreadsheetApp.openById("SPREADSHEET_ID").getActiveSheet().appendRow([new Date(),message]);
}
then it will become:
function master(){
// code that imports data from a form and organises it
logit("I'm in master now");
runMeAfterMaster();
logit("still in master but after calling runMeAfterMaster");
}
function runMeAfterMaster(){
logit("I'm in runMeAfterMaster now");
// code that should run after master
logit("getting out of runMeAfterMaster");
}
Harold's tips put me on the right path. The path to testing things out.
I placed my code in a code editor (in my case Brackets) and ran it through JSLint. To find any errors.
No errors there, even though the curly bracket at the end of the function name was red. It turns out over 100 lines of code in google apps and the curly bracket turns red. Under 100 lines you're good to go!
Unfortunately i couldn't debug.
So i decided to make it simpler and call both functions within a new one. That didn't work...and I still ignore why.
function MasterOfAll(){
Master();
runAfterMaster();
}
Second thing I did was to simply regroup both code of each function in a new one and call it. That worked.
function MasterOfAll(){
//Code from the Master function.
//Code from the runAfterMasterFunction.
}
Needless to say, I'm not a big fan of this solution (unclear, messy) but it works!
Related
having some issues with the HERE maps api outputting the data i'm requesting too many times. I need it to output only once every 10 seconds, however it is doing it far more times than that.
The code I have here is as follows:
function getMapCorners() {
var mapView = map.getViewModel();
var mapCorners = mapView.b.bounds.cb.X;
var corners = [mapCorners[9], mapCorners[10], mapCorners[3], mapCorners[4]];
console.log(corners);
}
map.addEventListener("mapviewchange", function () {
setTimeout(getMapCorners, 10000);
});
I need to grab these specific co-ordinates as this is feeding into another API that is creating markers on the map in specific areas. When zooming in, it does wait 10 seconds to run the function, but then it throws out the co-ordinate changes for every change in the map's view model during that 10 seconds.
The other API has a request limit of 100 every 15 minutes. So I need this to change so that it will run the function every 10 seconds, and it will only output the information for the final viewModel when the function runs.
If you want to run getMapCorners once every 10 seconds, then do this:
function doEveryTenSeconds(){
getMapCorners();
setTimeout(doEveryTenSeconds, 10000);
}
doEveryTenSeconds();
First, please don't use internal name of objects like .b.bounds.cb.X - b, cb, X are defined by compilation of js library and will be changed for new version of JS API. Please use for it a name of methods and objects described in documentation: https://developer.here.com/documentation/maps/3.1.29.0/api_reference/H.map.ViewModel.html#getLookAtData like:
var mapCorners = map.getViewModel().getLookAtData().bounds.getBoundingBox();
Second, the map event 'mapviewchange' runs multiply times during interacting with map therefore you get multiply times run of function getMapCorners. Suggestion to achieve what you want:
function getMapCorners() {
console.log("getMapCorners!!!", map.getViewModel().getLookAtData().bounds.getBoundingBox());
map.addEventListener("mapviewchange", onMapViewChange);
}
function onMapViewChange() {
map.removeEventListener("mapviewchange", onMapViewChange);
setTimeout(getMapCorners, 10000);
}
See please full code there on https://jsfiddle.net/1m8fvLjy/1/
I am developing a task application where the user inputs a task with a certain duration. I want to display a counter that shows for each task how much time the user has left. I have added the flyandi:reactive-countdown from the atmospherejs which works if I follow their example but in my case things are different. I have the following helper which returns the counter each seconds.
Template.tasks.helpers({
getCountdown: function() {
return countdown.get();
}
});
This is the counter variable which is GLOBAL otherwise it doesn't work.
var countdown = new ReactiveCountdown(30);
countdown.start(function() {
// do something when this is completed
});
As you can see in this case it uses a pre-defined value which is 30, but I want to use a variable. The problem is that the variable that I use to calculate how much time the user has left for that task is defined inside another function which makes her not accessible on a global scope. If I create that variable as global it doesn't work as it loads before the helper that I use to update its value.
Template.tasks.events({
'click #startTask':function(event){
console.log(this.taskName);
var duration=this.duration;
var numb = duration.match(/\d/g);
numb = numb.join("");
console.log(numb);
}
});
numb in this case is the time that the user has to finish the task but if I use something like new ReactiveCountdown(numb) this will display undefined as the script is run before the helper. Does anyone have any ideas?
I'm a beginner at this, so this error might be on account of faulty coding, but this is why I'm here! lol.
I have written a Sheets function that (in theory) would go through all the files in a particular folder and find all the instances of a particular word and then return the number of instances of that word. Here is the code I wrote:
function commentCount(name) {
var files = DocsList.getFolderById('FOLDER ID GOES HERE').getFiles();
var counter = 0;
for(i in files) {
var doc = DocumentApp.openById(files[i].getId());
var text = doc.getText();
text = text.replace( /\./g, "" );
var textArray = text.split(" ");
for(w in textArray){
if(textArray[w] == name){
counter++;
}
}
}
return counter;
}
When I call the function in Sheets, an error reads - Error: You do not have permission to call getFolderById (line 3, file "commentCount")
I've tried using getFolder("Folder name"), and getFolder(path), and the same error occurs. It seems that the DocList functions are not working correctly.
Not sure what the issue is because everything seems fine when I debug the function.
I won't be able to figure out if the rest of my code is sound until I figure out this error. Any help would be greatly appreciated!
Phil Bozak clarified that formulas in Spreadsheets that call scripts functions do not get full permissions, which makes it impossible to use getFolderByID function in this case.
I'm no javascript guru, I'm having to call an external JS file twice in one page. The JS file includes a function. Having this function called twice (once in each JS include) breaks the functionality. So I thought I'd modify the 2nd instance to a different function name. This works to allow the first instance to work correctly but breaks the 2nd one (The one with the function changed).
The function name is address and I'm trying to work just exactly what else needs to be modified in this script to reflect the name change. I fear there are other mentions of "address" that is legitimate and not associated with the function name. I'm at my wits end and am just not sure. Anyone care to look at this JS and help me find which instances of the word address need to be changed to correctly reflect the one function and var name?
/**
* execute part
*/
$(document).ready(function(){
address.bindZipcodeFind();
});
var address = {
bindZipcodeFind: function(){
$('.zipcode-searcha').click(function(){
$('.zipcode-search-resulta').text("로딩중...");
$.get('http://www.nuvonoir.com/postalcode2/zipsearch-action.php',{
query: $('#dongNamea').val()
},function(data){
$('.zipcode-search-resulta').html(data);
address.bindPutAddress();
})
});
},
bindPutAddress: function(){
$('.zipcode-search-resulta a').click(function(){
$('[id=zipcode1a]').val($(this).parent().parent().find('.postcd1').text());
$('[id=zipcode2a]').val($(this).parent().parent().find('.postcd2').text());
$('[id=OrdAddra]').val(address.remove_useless_addr($(this).parent().parent().find('.address').text()));
address.hideZipcodeFinder();
$('[name=addr]').focus();
return false;
});
},
remove_useless_addr: function(address){
if(address.indexOf('~') != -1){
address = address.split(' ').slice(0,-1).join(' ');
}
return address;
},
hideZipcodeFinder: function(){
$('.zipcode-findera').slideUp();
}
}
If you have no way to mitigate including code twice, then there's the only option: write that function was called elsewhere:
global variable
invisible element with certain id
or even more magic things:
field in document object or document root node (html/body)
location hash (URL part after #)
cookie/sessionStorage based on document.lastModified (it is equal to page generating time on server) or anything remaining stable within one page load.
Example using global variable:
function once() {
if (window.myOnceFuncIsCalled) return;
// do the main work
window.myOnceFuncIsCalled = true;
}
I need to do a simple pdf with some 3D objects for an oral presentation. I made several views, each one with a camera viewpoint, an object and a display mode.
To avoid the need to manually switch between the different viewpoints with the context menu, I would like the viewpoints to switch automatically with a Timer (each viewpoint staying for a few seconds). And I would like to not have to touch the mouse at all (nor the keyboard), so I would like to have the playback started as soon as the page appears.
I found the javascript command runtime.setView(N,x) to switch to the x'th view among N, but I don't know where to put it (I don't want to define a function which will be called when I press a button, since I want everything to be automated). Also, I don't know how to pause for a few seconds.
Any help ? Thanks !
I believe you're looking for setInterval(fn, time) which will call a function periodically at a time interval that you set. I'm not familiar with the setView() method you mentioned, but here's some pseudo code that you would put in tags at the end of the document body.
function startSwitcher()
var viewNum = 0;
var maxViews = 5; // you set this to how many views there are
setInterval(function() {
++viewNum;
if (viewNum >= maxViews) {
viewNum = 0;
}
runtime.setView(N, viewNum); // you will have to figure out this line
}, 2000);
}
startSwitcher();
The 2000 is 2000 milliseconds and is the time interval between executing the function. You can put any number of milliseconds there.
The runtime.setView(N, viewNum) line is something you will have to figure out as I am not familiar with whatever library you're trying to use there. The operative part of this code is the viewNum variable which configures which view in rotation should be next.
I think the runtime.SetView(..) Methods works with the name of the view as a string instead of the viewnumber. I have this function in a Dokument-level script and it works for me:
// view is the name of the view for example "TopView"
function setView(view){
console.println("Navigating to view: "+view);
var pageIndex = this.pageNum;
var annotIndex = 0;
var c3d = this.getAnnots3D( pageIndex )[ annotIndex ].context3D;
c3d.runtime.setView(view, true);
}
Combine this with the setInterval(..) from jfriend00´s answer und you should get what you need.
Best regards