I have the following code and when I run it I get the right number of items in sheetFormulas (4), and the array values look correctly formed.
However, I get an error right after the sheetFormulas Browser.msgBox pops up, indicating the getRange().setFormulas line has an issue, but I can't see what it is.
function test(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var testingTarget = ss.getSheetByName("Testing");
var sheetFormulas = new Array();
for (l=0;l<10;l++) {
sheetRowCount = l + 2;
var monthlyTotalCompanyCosts = '=F' + sheetRowCount + '/$F$29*$I$14';
var monthlyTotalCompanyCostsPerEa = '=IFERROR(H' + sheetRowCount + '/C' + sheetRowCount + ')';
var monthlyMargin = '=D' + sheetRowCount + '-F' + sheetRowCount;
var monthlyMarginPctg = '=IFERROR(J' + sheetRowCount + '/D' + sheetRowCount + ')';
sheetFormulas.push(monthlyTotalCompanyCosts,monthlyTotalCompanyCostsPerEa,monthlyMargin,monthlyMarginPctg);
Browser.msgBox("sheetFormulas.length is: " + sheetFormulas.length);
Browser.msgBox("sheetFormulas is: " + sheetFormulas);
testingTarget.getRange(sheetRowCount,8,1,4).setFormulas(sheetFormulas);
sheetFormulas = [];
}
}
Any help is appreciated,
Phil
First, sheetFormulas has to be a 2D array. So try doing
/* Notice the [] around sheetFormulas */
testingTarget.getRange(sheetRowCount,8,1,4).setFormulas([sheetFormulas]);
If you still see other problems, then put your code inside a try{}catch{} block and print out the exception in the catch block.
I also suggest that you print out the formula using Logger.log() before setting it on the spreadsheet.
Related
I have noticed that the script is significantly faster when I comment out the line that calls setValues(). Not that it's a super big issue, but I am interested in the different ways (if any) that I could speed the process up. If anyone has some insight, I would greatly appreciate it! It would also help me see where I could make similar optimizations in other parts of my script.
Here is the code in question:
// import new value(s)
if ((numRaw - numDk) > 0) {
var iDate;
var lastRow = getLastDataRow(earSheet, columnToLetter(earSheet.getRange("EAR_DATES_RNG").getColumn()));
var distName = impSheet.getRange("A1").getValue().toString();
var defaultDept = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("All Lists").getRange("A2").getValue().toString();
impData.forEach(function (entry) {
iDate = new Date(entry[0]);
var newEar = earSheet.getRange("A" + lastRow + ":G" + lastRow).getValues(); // init copy
if (currData.get(iDate.getTime()) == null) {
newEar[0][0] = entry[0];
newEar[0][1] = distName;
newEar[0][6] = entry[1];
newEar[0][3] = "Royalties";
newEar[0][4] = defaultDept;
newEar[0][5] = "NOT SPECIFIED";
earSheet.getRange("A" + lastRow + ":G" + lastRow).setValues(newEar);
Logger.log("ADDED: " + entry[1] + " to row: " + lastRow);
addedNewData++;
lastRow++;
}
else {
Logger.log("EXISTING DATA FOUND: " + currData.get(iDate.getTime()));
}
});
}
Using Matt and Cooper's suggestions, I came up with this revised code which is significantly faster:
if ((numRaw - numDk) > 0) {
var iDate;
var prevLastRow = getLastDataRow(earSheet, columnToLetter(earSheet.getRange("EAR_DATES_RNG").getColumn()));
var currLastRow = getLastDataRow(earSheet, columnToLetter(earSheet.getRange("EAR_DATES_RNG").getColumn()));
var rangeSize = numRaw;
var distName = impSheet.getRange("A1").getValue().toString();
var defaultDept = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("All Lists").getRange("A2").getValue().toString();
var newEar = earSheet.getRange("A" + prevLastRow + ":G" + (prevLastRow + rangeSize - 1)).getValues(); // init copy
impData.forEach(function (entry) {
iDate = new Date(entry[0]);
if (currData.get(iDate.getTime()) == null) {
newEar[currLastRow-2][0] = entry[0];
newEar[currLastRow-2][1] = distName;
newEar[currLastRow-2][6] = entry[1];
newEar[currLastRow-2][3] = "Royalties";
newEar[currLastRow-2][4] = defaultDept;
newEar[currLastRow-2][5] = "NOT SPECIFIED";
Logger.log("ADDED: " + entry[1] + " to row: " + currLastRow);
addedNewData++;
currLastRow++;
}
else {
Logger.log("EXISTING DATA FOUND: " + currData.get(iDate.getTime()));
}
});
earSheet.getRange("A" + prevLastRow + ":G" + (prevLastRow + rangeSize - 1)).setValues(newEar);
}```
The function I'm working on does an optimisation of the force required by a rudder foil (stabilator) on an America's Cup AC75 yacht, to balance the longitudinal moments of the sail forces. This is done by altering the angle of the stabilator, from initially providing an upward (positive) force, then as sail forces increase, the stabilator has to create a downward (negative) force.
The stabilator angles are in a column, and when it is changed, other calculations work out if it balances the sail forces. If it doesn't, there is a "Delta" column that indicates a value whether the rudder foil needs to provide more/less force, via it's angle.
I tried using Named Ranges for the column of Angles, and another for Delta. The code should iterate through adding a bit more (or less) angle to the stabilator, and each time, check the Delta. My code is wrong.
What I need to do is get the Angle value of one Angle cell, incrementally increase/decrease it, then setValue of that cell. Next is to getValue of the corresponding Delta cell, to see if I'm at Zero (plus/minus a small amount). If not, via a while loop, I increase/decrease the Angle again, setValue, recheck the Delta, and so on.
My problem is that I do not know how to get the A1Notation of each cell in the Named Ranges as I iterate through it, so that I can repeatedly getValue and setValue for just the single cell at a time?
function c_Optimise_Stabilator() {
// Author: Max Hugen
// Date: 20102-12-07
// Purpose: Attempt to optimise Stab Angle to balance with Stab Target Force
/* WARNING: This function may eventually cause a circular reference, so ensure there is an "escape".
* May occur if other optimisation functions are also run?
* OPTIMISATION: Try in this order:
* 1. Optimise Transverse Moments
* 2. Optimise Stabilator
* 3. Check, and if necessary, rerun Optimise Transverse Moments
* 4. Check, and if necessary, rerun Optimise Stabilator
* If Optimise Stabilator returns all Angles OK, we're good!
*/
const ui = SpreadsheetApp.getUi();
const ss = SpreadsheetApp.getActiveSpreadsheet();
// var target_sheet = "Analysis";
// var sheet = ss.getSheetByName("Analysis");
var msg = ""; // gather input for Logger
var s = ""; // short info for testing alerts, then added to msg
var log = true; // whether to output msg to the Logger
// angle range
const maxAngle = 2.0, minAngle = -0.2, incAngle = 0.1;
//limits
var maxLoopIterations=10; // to avoid excessive iterations
var minDelta=0.02; // to limit the minimum size of Delta tested
// counters
var i=0, loopIterations=0;
// Original and New Vals
var originalAngle=0.0, newAngle=0.0, originalDelta=0.0, newDelta=0.0;
// ranges used in getRange - variable here, for testing. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/*
var sAngle = "Optimise_Stab_Angle";
var sDelta = "Optimise_Stab_Delta";
var sAngle = "Analysis!AF14:AG14"; // 1 rows (but only 2 cols now) - failing
var sDelta = "Analysis!AM14:AM14";
*/
var sAngle = "Analysis!AF10:AG13"; // 4 rows
var sDelta = "Analysis!AM10:AM13";
var rAngle = ss.getRange(sAngle);
var dAngle = rAngle.getValues();
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
originalAngle = Math.round(dAngle[i][1]*1000)/1000;
originalDelta = Math.round(dDelta[i][0]*1000)/1000;
var iLen = rAngle.getNumRows();
for(i=0; i<iLen; i++){
s = "";
newAngle = originalAngle;
s += " Vb: " + dAngle[i][0] + "; Original Angle: " + originalAngle + "; originalDelta: " + originalDelta + "\r\n";
// if stabilator force is below target (negative Delta), increase stab angle unless at maxAngle.
if ( Math.abs(Math.round(dDelta[i][0]*100)/100) > minDelta && originalAngle < maxAngle) {
loopIterations = 1;
while (newAngle <= maxAngle) {
try {
if ( newAngle == maxAngle ) {
s += " MAX.ANGLE: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
// Have to update the Delta range, to check if Delta still too high/low
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
newDelta = Math.round(dDelta[i][0]*1000)/1000;
if ( Math.abs(Math.round(newDelta*100)/100) < minDelta ) {
s += " COMPLETED: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
if ( loopIterations > maxLoopIterations ) {
s += " EXCEEDED maxLoopIterations of " + maxLoopIterations;
break;
}
} catch(err) {
Logger.log (c_ErrorToString (err) + "\n" + "Vb: " + dAngle[i][0]);
}
newAngle += incAngle; // for some reason, this may STILL produce a number like 1.400000003 (example only)
newAngle = Math.round(newAngle*1000)/1000;
// set the new angle
dAngle[i][1] = newAngle;
// update the iteration count
loopIterations ++
}
}
// if stabilator force is above target (positive Delta), decrease stab angle unless at minAngle.
else if ( Math.abs(Math.round(dDelta[i][0]*100)/100) > minDelta && originalAngle > minAngle) {
loopIterations = 1;
while (newAngle >= minAngle) {
try {
if ( newAngle == minAngle ) {
s += " MIN.ANGLE: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
// Have to update the Delta range, to check if Delta still too high/low
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
newDelta = Math.round(dDelta[i][0]*1000)/1000;
if ( Math.abs(Math.round(newDelta*100)/100) < minDelta ) {
s += " COMPLETED: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
if ( loopIterations > maxLoopIterations ) {
s += " EXCEEDED maxLoopIterations of " + maxLoopIterations;
break;
}
} catch(err) {
Logger.log (c_ErrorToString (err) + "\n" + "Vb: " + dAngle[i][0]);
}
newAngle -= incAngle; // for some reason, this may STILL produce a number like 1.400000003 (example only)
newAngle = Math.round(newAngle*1000)/1000;
// set the new angle
dAngle[i][1] = newAngle;
// update the iteration count
loopIterations ++
}
}
msg += s + "\r\n";
}
rAngle.setValues(dAngle);
msg = "c_Optimise_Stabilator \r\n" + msg
Logger.log(msg);
ui.alert(msg);
}
Found the way to get the cell A1Notation, use getCell() on the range, then getA1Notation.
cellA1 = range.getCell(1, 1).getA1Notation();
So I figured out how to update the value of the database, but the another problem came up. When I'm trying to update the value of a certain in the table, the output is that it updated all the values. I'm not getting the correct key when a certain button is pressed for the update. Can you guys help me with this?
My .html file
var rootRef = firebase.database().ref().child("REPORTS").child('05-21-2017');
rootRef.on("child_added", function(snapshot){
var date = snapshot.child("dateAndTime").val();
var lat = snapshot.child("latitude").val();
var long = snapshot.child("longitude").val();
var link = snapshot.child("link").val();
var report = snapshot.child("report").val();
var status = snapshot.child("status").val();
var needs = snapshot.child("needs").val();
var key = snapshot.key;
console.log(key);
var updateData = "updateData()";
$("#table_body").append("<tr id='"+snapshot.key+"'><td>"+snapshot.key+"</td><td>" +date+"</td><td>"+report+"</td><td>"+lat+"</td><td>"+long+"</td><td>"+status+"</td><td>"+needs+"</td><td><button onclick = "+updateData+">update</button></td></tr>");
});
My .js file
function updateData(key) {
var rootRef = firebase.database().ref().child("REPORTS").child('05-21-2017');
rootRef.on("child_added", function(snapshot){
var rootRef2 = firebase.database().ref().child("REPORTS").child('05-21-2017/'+snapshot.key);
console.log(rootRef2);
rootRef2.update({status: "Ongoing"});
console.log("success");
});
}
Here is what my table looks like
I want to change a particular table when i click the update button. Please help me, badly needed.
const ulTable = document.getElementById('tabla');
//Create references
const dbRefObject = firebase.database().ref().child('Users');
//Sync table changes
dbRefObject.on('child_added', snap => {
var gear = snap.child('Gear').val();
var level = snap.child('Level').val();
var strength = snap.child('Strength').val();
$(ulTable).append("<tr id="+snap.key+"><td>" + gear + "</td><td>" + level + "</td><td>" + strength + "</td></tr>");
}); //child_added
dbRefObject.on('child_changed', snap => {
var gear = snap.child('Gear').val();
var level = snap.child('Level').val();
var strength = snap.child('Strength').val();
$("#"+snap.key).html("<td>" + gear + "</td><td>" + level + "</td><td>" + strenght + "</td>");
}); //child_changed
dbRefObject.on('child_removed', snap => {
var gear = snap.child('Gear').val();
var level = snap.child('Level').val();
var strength = snap.child('Strength').val();
$("#"+snap.key).html("<td>" + gear + "</td><td>" + level + "</td><td>" + strenght + "</td>").remove();
});
My DB is:
Users -> (Gear, Level, Strength)
When I run the application from Flash Develop everything is fine, both in Debug and Release.
After the application is packaged and installed, I just get a black screen when run.
However if I add a 'debug' file to applicationDirecty\META-INF\AIR\debug the application runs normally.
What could be causing this? and how can it be solved?
A debugging utility seemed to be causing the problem in the release build... removing calls to this solved the issue.
/** Gets the name of the function which is calling */
public function Log(prefix:String = "", suffix:String = "", params:* = null):void
{
var error:Error = new Error();
var stackTrace:String = error.getStackTrace(); // entire stack trace
var startIndex:int = stackTrace.indexOf("at ", stackTrace.indexOf("at ") + 1); //start of second line
var endIndex:int = stackTrace.indexOf("()", startIndex); // end of function name
var lastLine:String = stackTrace.substring(startIndex + 3, endIndex);
var functionSeperatorIndex:int = lastLine.indexOf('/');
var ClassSeperatorIndex:int = lastLine.indexOf(':');
var objectName:String = lastLine.substring(ClassSeperatorIndex+2, functionSeperatorIndex);
var functionName:String = lastLine.substring(functionSeperatorIndex + 1, lastLine.length);
trace(prefix +" " + "[" + objectName + "]" + " > " + functionName + " " + suffix);
}
Open Run.bat and replace
set OPTIONS=-connect %DEBUG_IP%
with
set DEBUG_IP=%DEBUG_IP%
I am looking to understand how to update a jqGrid table from Fusion Tables (FT) -
at the moment I can search or scroll on a Google Map, send an event listener that compiles a FT query of the spatial bounds of the viewport/map, to get a new set of results.
I want to use the new FT query string (or could use the Google code to retrieve the data - query.send(getData);) to update the jqGrid table with the new values.
Before I started using jqGrid, I tried/suceeded with the Google Visualisation API, and some of that code is below. Could anyone suggest how to move from table.draw, to loading/reloading a jqGrid table? Thanks a lot in advance.
function tilesLoaded() {
google.maps.event.clearListeners(map, 'tilesloaded');
google.maps.event.addListener(map, 'zoom_changed', getSpatialQuery);
google.maps.event.addListener(map, 'dragend', getSpatialQuery);
getSpatialQuery();
}
function getSpatialQuery() {
sw = map.getBounds().getSouthWest();
ne = map.getBounds().getNorthEast();
var spatialQuery = "ST_INTERSECTS(latitude, RECTANGLE(LATLNG(" + sw.lat() + "," + sw.lng() + "), LATLNG(" + ne.lat() + "," + ne.lng() + ")))";
changeDataTable(spatialQuery);
}
function changeDataTable(spatialQuery) {
var whereClause = "";
if(spatialQuery) {
whereClause = " WHERE " + spatialQuery;
}
var queryText = encodeURIComponent("SELECT 'latitude', 'longitude', 'name' FROM xxxxxxxx" + whereClause + " LIMIT 50");
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
query.send(getData);
}
function getData(response) {
var table = new google.visualization.Table(document.getElementById('visualization'));
table.draw(response.getDataTable(), {showRowNumber: true});
}
Oh, and I used Oleg's code jqGrid returns blank cells as a basis for just seeing if I could get a simple multi-select table to pull data from my FT - that worked fine with the simple mod of
url: 'http://www.google.com/fusiontables/api/query?sql=' +
In case this helps someone, I've taken some of the code I came up with and pasted it below:
// You can get the map bounds via then pass it via a function (below is hacked from several functions
sw = map.getBounds().getSouthWest();
ne = map.getBounds().getNorthEast();
var whereClause = "ST_INTERSECTS(latitude, RECTANGLE(LATLNG(" + sw.lat() + "," + sw.lng() + "), LATLNG(" + ne.lat() + "," + ne.lng() + ")))";
//construct the URL to get the JSON
var queryUrlHead = 'http://www.google.com/fusiontables/api/query?sql=';
var queryUrlTail = '&jsonCallback=?'; //
var queryOrderBy = ' ORDER BY \'name\' ASC';
var queryMain = "SELECT * FROM " + tableid + whereClause + queryOrderBy + " LIMIT 100";
var queryurl = encodeURI(queryUrlHead + queryMain + queryUrlTail);
//use the constructed URL to update the jqGrid table - this is the part that I didn't know in my above question
$("#gridTable").setGridParam({url:queryurl});
$("#gridTable").jqGrid('setGridParam',{datatype:'jsonp'}).trigger('reloadGrid');