try/catch did not catch error in google sheet - try-catch

I try the code to detect hidden row by Esquinas ( http://gist.github.com/esquinas/bdc8de88a41f08cc128f00341857b0e5) which use a try/catch approach.
function myfunction(){
var sheet = SpreadsheetApp.getActiveSheet();
var result = isRowHidden(sheet.getRange("A2"));
Logger.log(result);
}
function isRowHidden (row, optionalSheet) {
var ss = SpreadsheetApp.getActive()
var sheet = optionalSheet || ss.getActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var dup = ss.duplicateActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var isHidden = false
var rowIndex = row.getRow()
var numRows = dup.getMaxRows()
if (numRows === 1) {
ss.deleteSheet(dup)
return false
}
try {
if (rowIndex === numRows ) {
dup.hideRows(1, numRows - 1)
} else if (rowIndex === 1) {
dup.hideRows(rowIndex + 1, numRows - 1)
} else {
dup.hideRows(1, rowIndex - 1)
dup.hideRows(rowIndex + 1, numRows - rowIndex)
}
isHidden = false
} catch (err) {
Logger.log("There is error: " + err.message)
isHidden = true
} finally {
Logger.log("finall");
ss.deleteSheet(dup)
}
return isHidden
}
I created a sheet with 3 rows and hide the 2nd row. However, the error could not be caught. This is the result I got and I can't figure out the problem
Execution log
11:28:25 AM Notice Execution started
11:28:26 AM Error
Exception: You can't hide all the rows on the sheet.
isRowHidden # test.gs:37
myfunction # test.gs:4

Related

Can you help me create a Google Apps Script that will return values from a database to an on-sheet form?

My issue is returning the values saved in a database to the form in each cell in the range. The saveToDB script below is able to save the values from the form to the database, but I don't know how to retrieve those values. Hope you could help me. Thanks so much!
Form: sample form
Database: database sample
function saveToDB(){
range = ["C2","C4","C6"]
var newRange = range.map(f => formSheet.getRange(f).getValue())
dbSheet.appendRow(newRange)
}
function loadToForm(){
range = ["C2","C4","C6"]
var dbArray = dbSheet.getRange(2,1,dbSheet.getLastRow(),dbSheet.getLastColumn()).getValues()
var newArray = dbArray.filter(function(row){
if(row[0] === "Fred" && row[0] !== -1){
return row !== ""
}
})
//Don't know how to return each value to each cell in the range
//Update - this is the code that did it
range.map((f,i) => formSheet.getRange(f).setValue(newArray[0][i]))
}
function saveToDB() {
const ss = SpreadsheetApp.getActive();
const fsh = ss.getSheetByName('Form Sheet Name');
const dsh = ss.getSheetByName('Database Sheet Name')
let arr = ["C2", "C4", "C6"].map(e => fsh.getRange(e).getValue());
dsh.appendRow(arr);
}
function loadToForm() {
const range = ["C2", "C4", "C6"];
const ss = SpreadsheetApp.getActive();
const dsh = ss.getSheetByName('Database Sheet Name');
const fsh = ss.getSheetByName('Form Sheet Name');
let r = SpreadsheetApp.getUi().prompt('Row Number','Enter Row Number', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(r.getSelectedButton() == SpreadsheetApp.getUi().Button.OK) {
let vs = dsh.getRange(row, 1, 1, dsh.getLastColumn()).getValues()[0];
range.forEach((e,i) => { fsh.getRange(e).setValue(vs[i])
});
}
}
All you have to do is use the setValue() function and iterate through each cell like so:
function loadToForm(){
range = ["C2","C4","C6"]
var dbArray = dbSheet.getRange(2,1,dbSheet.getLastRow(),dbSheet.getLastColumn()).getValues()
var newArray = dbArray.filter(function(row){
if(row[0] === "Fred" && row[0] !== -1){
return row !== ""
}
})
//Remove useless extra dimension from array
newArray = newArray[0];
//Solution 1 using RangeList
var ranges = formSheet.getRangeList(range).getRanges();
for(var i in newArray){
ranges[i].setValue(newArray[i]);
}
//Solution 2 not using RangeList
for(var i in newArray){
formSheet.getRange(range[i]).setValue(newArray[i]);
}
}

Trying to create a service to build my NgTable

I'm trying to create a service that return me the NgTableParams so I don't need to do it every time I need a table.
I was able to do it and it worked, but only if i have only one table using it in my controller, if I try to use it in a second table look's like the service mess the parameters of the fist and second table and stop working.
I tried to change the service to a factory and tried to make a angular.copy of the service so each copy create one different table yet noting worked.
Every time i need a table it is like this:
$scope.tableParams = NgTableDataService.getGenericTableParams($scope.onboardcomputerstatus, $scope.filterObject);
$scope.searchTable = { filter: '' };
$scope.tableParams = new NgTableParams({
count: $scope.session.user.tablePagination,
filter: $scope.searchTable.filter
}, {
counts: rowsPerPageTemplate,
getData: function (params) {
var funcFilter = function (item) {
var pfilter = params.filter().filter.toUpperCase();
return item.onboardComputer.id.toString().indexOf(pfilter) >= 0
|| (!!item.onboardComputer.remainingMonitoringMsgs ? item.onboardComputer.remainingMonitoringMsgs : "").toString().indexOf(pfilter) >= 0
|| $filter('date')((!!item.onboardComputer.oldestMonitoringTimestamp ? item.onboardComputer.oldestMonitoringTimestamp : ""), Session.get().company.dateHourFormatHTML).indexOf(pfilter) >= 0
|| $filter('date')((!!item.lastCommunicatio ? item.lastCommunicatio : ""), Session.get().company.dateHourFormatHTML).indexOf(pfilter) >= 0
|| $filter('date')((!!item.lastRegister ? item.lastRegister : ""), Session.get().company.dateHourFormatHTML).indexOf(pfilter) >= 0
|| item.vehicle.code.toUpperCase().indexOf(pfilter) >= 0
|| item.vehicle.name.toUpperCase().indexOf(pfilter) >= 0;
}
filteredData = params.filter() ? $filter('filter')($scope.onboardcomputerstatus, funcFilter) : $scope.onboardcomputerstatus;
if (!!filteredData && filteredData.length >= 0) {
params.total(filteredData.length);
var rowsPerPageTemplateWithAllData = rowsPerPageTemplate.slice();
var isFound = rowsPerPageTemplateWithAllData.some(function (element) {
return element === filteredData.length;
});
var filteredDataLength = filteredData.length + (isFound ? 1 : 0);
rowsPerPageTemplateWithAllData.push(filteredDataLength);
params.settings().counts = rowsPerPageTemplateWithAllData;
if (params.count() === MY_CONSTANTS.TABLE_PAGINATION_ALL) {
params.count(filteredDataLength);
}
if (params.total() <= params.count()) {
params.page(1);
}
var x = $filter('orderBy')(filteredData, params.orderBy());
var y = x.slice((params.page() - 1) * params.count(), params.page() * params.count());
return y;
} else {
return null;
}
}
});
So I tried to do a factory like this:
angular.module('control-room').factory('NgTableDataFactory', function (
$filter, MY_CONSTANTS, NgTableParams, Session
) {
var ngTableObj = {};
ngTableObj.tableData = {};
ngTableObj.filterObject = {};
ngTableObj.session = Session.get();
ngTableObj.defaultDateFormat = (!!ngTableObj.session.company ? ngTableObj.session.company.dateHourFormatHTML : null);
ngTableObj.tablePagination = (!!ngTableObj.session.user ? ngTableObj.session.user.tablePagination : MY_CONSTANTS.QTD_REG_TAB_INDEX);
ngTableObj.NgTableParamsFactory = new NgTableParams({
count: ngTableObj.tablePagination,
filter: ""
}, {
counts: rowsPerPageTemplate,
getData: function (params) {
if (!!params.filter().filter && params.filter().filter != '') {
var pfilter = params.filter().filter.toUpperCase();
} else {
var pfilter = '';
}
let filteredData = params.filter() ? $filter('filter')(ngTableObj.tableData, ngTableObj.funcFilterFactory(ngTableObj.filterObject, pfilter)) : ngTableObj.tableData;
if (!!filteredData && filteredData.length >= 0) {
params.total(filteredData.length);
var rowsPerPageTemplateWithAllData = rowsPerPageTemplate.slice();
var isFound = rowsPerPageTemplateWithAllData.some(function (element) {
return element === filteredData.length;
});
var filteredDataLength = filteredData.length + (isFound ? 1 : 0);
rowsPerPageTemplateWithAllData.push(filteredDataLength);
params.settings().counts = rowsPerPageTemplateWithAllData;
if (params.count() === MY_CONSTANTS.TABLE_PAGINATION_ALL && filteredDataLength > 0) {
params.count(filteredDataLength);
}
var x = $filter('orderBy')(filteredData, params.orderBy());
var y = x.slice((params.page() - 1) * params.count(), params.page() * params.count());
return y;
} else {
return null;
}
}
});
ngTableObj.findPropertyValue = function (obj, propertyList){
let aux = obj;
for(property of propertyList){
aux = aux[property];
}
return aux
};
ngTableObj.funcFilterFactory = function (f_Object, p_filter) {
return function (item) {
var result = false;
if (!!f_Object.columnNames) {
f_Object.columnNames.forEach(function (row) {
if (!result){
const propertyValue = ngTableObj.findPropertyValue(item, row.split('.'));
result = (propertyValue ? propertyValue.toString() : "").toUpperCase().indexOf(p_filter) >= 0 || result;
}
});
};
if (!!f_Object.translateNames) {
f_Object.translateNames.forEach(function (row) {
if (!result){
const propertyValue = ngTableObj.findPropertyValue(item, row.split('.'));
result = $filter('translate')((propertyValue != null ? propertyValue.toString() : "").toUpperCase()).indexOf(p_filter) >= 0 || result;
}
});
}
if (!!f_Object.dateFormat) {
f_Object.dateFormat.forEach(function (row) {
if (typeof(row) == 'string') {
if (!result) {
const propertyValue = ngTableObj.findPropertyValue(item, row.split('.'));
result = propertyValue ? $filter('date')(propertyValue, ngTableObj.defaultDateFormat).toUpperCase().indexOf(p_filter) >= 0 : false || result;
}
}else {
if (!result) {
const propertyValue = ngTableObj.findPropertyValue(item, row[0].split('.'));
result = propertyValue ? $filter('date')(propertyValue, row[1]).toUpperCase().indexOf(p_filter) >= 0 : false || result;
}
}
});
}
return result;
};
};
return ngTableObj
});
and in the controller is like this:
$scope.filterObject = {
columnNames : ['onboardComputer.id', 'onboardComputer.remainingMonitoringMsgs', 'vehicle.code', 'vehicle.name' ],
dateFormat : ['onboardComputer.oldestMonitoringTimestamp', 'lastCommunicatio', 'lastRegister' ]
};
$scope.tableFactory = NgTableDataFactory;
$scope.tableFactory.tableData = $scope.onboardcomputerstatus;
$scope.tableFactory.filterObject = $scope.filterObject;
$scope.tableFactory.session = Session.get();
$scope.tableParams = $scope.tableFactory.NgTableParamsFactory
Like I said, this way it work well, but only if i use one time, if I have 2 tables it stop working

look at all instances of an array in a if statement?

I have about 20 different sheets and I wrote some google script to combine all of the data into a master sheet. Now I'd like like to be able to exclude certain sheets. My idea to do this was to storage the names of those sheet in a variable. This is what I have so far, but I am getting an error? Any ideas?
label is the name of the Column that I am scanning each sheet for and masterSheetName is the sheet where I am storing the data.
if (sheetName !== masterSheetName && sheetName !== skippedsheets)
lines are the ones I am having trouble with. It is not going though all of the instances of skipped sheets.
Is there a way to do this with a for each loop?
function getColVals(label, masterSheetName) {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var colValues = []
for ([i,sheet] in sheets) {
var sheetName = sheet.getSheetName();
var skippedsheets = ["HHS 1","HHS 2"];
Logger.log(skippedsheets);
Logger.log(skippedsheets[0]);
if (sheetName !== masterSheetName && sheetName !== skippedsheets) {
var colValues2 = getColValues(label,sheetName);
colValues = colValues.concat(colValues2);
}
}
return colValues;
}
thank you,
Jerome
I found this function called inArray that some one wrote and shared and it worked perfectly.
function getColVals(label, masterSheetName) {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var colValues = []
for ([i,sheet] in sheets) {
var sheetName = sheet.getSheetName();
var skippedsheets = ["template","intro","games"];
// Logger.log(skippedsheets);
// Logger.log(skippedsheets[0]);
if (sheetName !== masterSheetName && !(skippedsheets.inArray(sheetName))) {
var colValues2 = getColValues(label,sheetName);
colValues = colValues.concat(colValues2);
Logger.log(sheetName);
}
}
return colValues;
}
/*
* #function
* #name Object.prototype.inArray
* #description Extend Object prototype within inArray function
*
* #param {mix} needle - Search-able needle
* #param {bool} searchInKey - Search needle in keys?
*
*/
Object.defineProperty(Object.prototype, 'inArray',{
value: function(needle, searchInKey){
var object = this;
if( Object.prototype.toString.call(needle) === '[object Object]' ||
Object.prototype.toString.call(needle) === '[object Array]'){
needle = JSON.stringify(needle);
}
return Object.keys(object).some(function(key){
var value = object[key];
if( Object.prototype.toString.call(value) === '[object Object]' ||
Object.prototype.toString.call(value) === '[object Array]'){
value = JSON.stringify(value);
}
if(searchInKey){
if(value === needle || key === needle){
return true;
}
}else{
if(value === needle){
return true;
}
}
});
},
writable: true,
configurable: true,
enumerable: false
});

I cant break my foreach with ajax inside

I have this:
var addresses_tmp = addresses.slice();
var final_addresses = [];
addresses.forEach(function (current_address, i) {
var near_addresses = [];
near_addresses.push(current_address);
addresses_tmp.forEach(function (next_address, j) {
if (current_address.address.info.code != next_address.address.info.code) {
var data = {
key : $scope.MicrosoftKey,
optmz : "distance",
routeAttributes : "routePath"
}
data["wp.0"] = current_address.address.location.lat + "," + current_address.address.location.lng;
data["wp.1"] = next_address.address.location.lat + "," + next_address.address.location.lng;
ajax.sendApiRequest(data, "GET", "http://dev.virtualearth.net/REST/V1/Routes/Driving", is_url=true).then(
function(response) {
var distance = response.data.resourceSets[0].resources[0].travelDistance;
if (distance < 0.020) {
near_addresses.push(next_address);
addresses_tmp.splice(j, 1);
}
if (j == addresses.length - 1) {
final_addresses.push(near_addresses);
if (near_addresses.length == 1) {
addresses_tmp.splice(j, 1);
}
addresses_tmp.splice(i, 1);
}
// if (count == addresses.length * addresses.length) {
// console.log("ya he acabado todasssss")
// }
},
function(error) {
console.log("error", error);
}
)
}
})
})
And I would like to break all function when the first foreach and the second foreach are finished but I cant put if condition to do this.
As I have ajax inside the second foreach, my variables are crazy so I cant put an if condition to break it.
I need to do this because I am compare two arrays and getting distance between two points (one in the first array and second in the other array)

Ext JS EditorGridPanel - How to split cell to show multiple rows

In Ext.grid.EditorGridPanel table how to split a cell to have two or three rows?
Like the below image
I managed to do a kind of rowspan instead of row splitting. IMO it's easier and it looks the same as grid on attached image. Example code:
var grid = new Ext.grid.EditorGridPanel({
[...],
// hook up events
initComponent: function () {
Ext.grid.GridPanel.prototype.initComponent.call(this);
this.getView().on('refresh', this.updateRowSpan, this);
this.getView().on('rowupdated', this.updateRowSpan, this);
},
onLayout : function(vw, vh) {
this.updateRowSpan();
},
// set span on rows
updateRowSpan: function() {
var columns = this.getColumnModel().config,
view = this.getView(),
store = this.getStore(),
rowCount = store.getCount(),
column = columns[0], // put propert column index here
dataIndex = column.dataIndex,
spanCell = null,
spanCount = null;
spanValue = null;
for (var row = 0; row < rowCount; ++row) {
var cell = view.getCell(row, 0),
record = store.getAt(row),
value = record.get(dataIndex);
if (spanValue != value) {
if (spanCell !== null) {
this.setSpan(Ext.get(spanCell), spanCount);
}
spanCell = cell;
spanCount = 1;
spanValue = value;
} else {
spanCount++;
}
}
if (spanCell !== null) {
this.setSpan(Ext.get(spanCell), spanCount);
}
},
// set actual span on row
setSpan: function(cell, count) {
var view = this.getView(),
innerCell = Ext.get(cell.down('*')),
height = cell.getHeight(),
width = cell.getWidth();
cell.setStyle('position', 'relative');
if (count == 1) {
innerCell.setStyle('position', '');
innerCell.setStyle('height', '');
innerCell.setStyle('height', '');
} else {
innerCell.setStyle('position', 'absolute');
innerCell.setStyle('height', (height * count - cell.getPadding('tb') - innerCell.getPadding('tb')) + 'px');
innerCell.setStyle('width', (width - cell.getPadding('lr') - innerCell.getPadding('lr')) + 'px');
}
}
});
This code changes style of .x-grid3-cell-inner by applying position: absolute and big enough size to cover rows below. Notice that you must also apply some opaque background to make it work. Working sample: http://jsfiddle.net/RpxZ5/8/
I first wrote code for Ext JS 4, if you interested, here is working sample: http://jsfiddle.net/wQSQM/3/

Resources