Dynamic report columns in BIRT - birt

I have a BIRT report, which simply selects all the columns of a table. Every time a new column is added to the table I have to modify the report to visualize the new column. Is it possible somehow to show the result of a "select * from table" query in the report, so I shouldn't modify the report template anymore? The order of columns is not important.
Thank You.

This is not directly possible.
However, using the DE API, you can create and save a new rptdesign file based on the query, then in a second step execute that report.
The example at https://www.eclipse.org/birt/documentation/integrating/deapi.php only shows how to create layout items, but you can as well create Data Sources and Data Sets.
This is a bit tricky however, so unless you need this quite often, it is not worth the effort.
Here is an excerpt from a script I am using in a file sql2rptdesign.rptdesign to create a new report design. This should give you an idea:
importPackage(Packages.org.eclipse.birt.data.engine.api);
importPackage(Packages.org.eclipse.birt.data.engine.core);
importPackage(Packages.org.eclipse.birt.report.model.api);
importPackage(Packages.org.eclipse.birt.report.model.api.elements.structures);
importPackage(Packages.org.eclipse.birt.report.model.api.util);
importPackage(Packages.org.eclipse.birt.data.engine.api.querydefn);
var engine = reportContext.getReportRunnable().getReportEngine();
var myconfig = reportContext.getReportRunnable().getReportEngine().getConfig();
var designFactory = designHandle.getElementFactory();
// Ein neues DataSet anlegen
var de = DataEngine.newDataEngine( myconfig, null );
var dsrc = reportContext.getDesignHandle().findDataSource("lisa");
var dsHandle = designFactory.newOdaDataSet("Main", "org.eclipse.birt.report.data.oda.jdbc.JdbcSelectDataSet" );
dsHandle.setDataSource(dsrc.getName());
dsHandle.setQueryText(sql);
designHandle.getDataSets( ).add( dsHandle );
Then I add the output columns (I parsed the SQL statement beforehand to get the necessary information). I don't know if this is strictly needed.
var numColumns = 0;
for (var position=0; position<rows.length; position++) {
var row = rows[position];
var colName = row[0];
if (colName == "__Template") {
continue;
}
var colTyp = row[1];
var colWidth = row[2];
var resultCol = new OdaResultSetColumn();
resultCol.setColumnName(colName);
resultCol.setNativeName(colName);
resultCol.setDataType(colTyp);
resultCol.setPosition(position+1);
numColumns = position + 1;
dsHandle.getPropertyHandle(DataSetHandle.RESULT_SET_PROP).addItem(resultCol);
var resultHint = new ColumnHint();
resultHint.setProperty(ColumnHint.COLUMN_NAME_MEMBER, colName);
dsHandle.getPropertyHandle(DataSetHandle.COLUMN_HINTS_PROP).addItem(resultHint);
}
And then add a table, its column bindings, columns, detail rows and cell contents to the layout. This is a bit lenghty.
// Tabellarisches Layout
var elementFactory = designHandle.getElementFactory();
var body = designHandle.getBody();
var tab = elementFactory.newTableItem("Main", numColumns);
tab.setDataSet(dsHandle);
tab.pageBreakInterval = 9999;
for (var colNum=0; colNum<numColumns; colNum++) {
var r = rows[colNum];
var colName = r[0];
var colNameSlashes = addSlashes(colName);
var colType = r[1];
var width = r[2];
var pattern = r[3];
var align = r[4];
// Binding
var colBinding = StructureFactory.createComputedColumn( );
colBinding.setName(colName);
colBinding.setExpression( 'dataSetRow[' + colNameSlashes + ']');
colBinding.setDataType(colType);
tab.addColumnBinding(colBinding, true);
// Überschrift
var textdata = elementFactory.newTextData(null);
textdata.setContentType("plain");
textdata.setValueExpr(colNameSlashes);
textdata.setStringProperty("whiteSpace", "normal");
tab.getLayoutModel().getCell(1,colNum+1).getContent().add(textdata);
// Wert
var textdata = elementFactory.newTextData(null);
textdata.setContentType("plain");
textdata.setHasExpression(true);
textdata.setStringProperty("whiteSpace", "normal");
var expr = 'row[' + colNameSlashes + ']';
textdata.setValueExpr(expr);
tab.getLayoutModel().getCell(2,colNum+1).getContent().add(textdata);
// Spaltenbreite und Ausrichtung
var columnHandle = tab.getColumns().get(colNum); // 0-basiert?
if (width) {
columnHandle.setProperty("width", StringUtil.parse(width));
}
}
body.add(tab, 0);
And finally save the new file:
designHandle.saveAs(designFilename);
However, this doesn't use a template as you would like to do.

Related

Is there a way to use fusion algorithms like STARFM in Google Earth Engine?

Landsat and MODIS products both have their advantages. Landsat with its high spatial resolution and MODIS with its high temporal resolution. I've read a lot about downloading the files and fuse them locally with algorithms like STARFM in Python for example. Is there a way to fuse both collections directly in Google Earth Engine to save computational time?
There is Google earth engine code in GitHub. The link is below:
https://github.com/MacGallagher/GEE_STARFM_FUSION
The code I copied is below:
/**** Start of imports. If edited, may not auto-convert in the playground. ****/
var l8 = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR"),
modis = ee.ImageCollection("MODIS/006/MOD09GQ"),
geometry4 = /* color: #d63000 */ee.Geometry.Polygon(
[[[-116.004638671875, 42.809506838324204],
[-115.59539794921875, 42.78129125156276],
[-115.499267578125, 43.004647127794435],
[-115.499267578125, 43.28920196020127],
[-116.00189208984375, 43.35114690203121],
[-116.19415283203125, 43.07691312608711]]]),
geometry = /* color: #98ff00 */ee.Geometry.Polygon(
[[[-115.93391418457031, 43.09346209534859],
[-115.80276489257812, 43.095718426590174],
[-115.80276489257812, 43.161366298103566],
[-115.9332275390625, 43.16086543618915]]]);
/***** End of imports. If edited, may not auto-convert in the playground. *****/
// based on script by Faye Peters, University of Louisville
// modified by Megan Gallagher, Boise State University
// for code inquiries, or adjustments please email megangallagher#u.boisestate.edu
// code exists for:
// landsat 5,7, and 8 NDVI merging with MODIS Terra daily
// MODIS Terra and Sentinel-2
// Landsat pre tier and modis daily terra - works with base R code
// Landsat 8 and Sentinel-2
////////////////////////////////////////Variables//////////////////////////////////////////////
// import Landsat 8 and MODIS daily terra surface reflectance 250m
var region = geometry; //region you want to export
var bounds = geometry4 //outer bounds of image to catch boundary effect, make larger than region
var date_begin = '2016-03-02' //start date of data collection, must be a landsat image date
var date_end ='2016-10-13' // end date of data collection, must be the day AFTER last landsat image
var csv_title = '2016_Dates_BOP' //title of csv output
var ls_title = '2016_landsat' // title of landsat tif file
var mod_title = '2016_mod' // title of modis tif file
/////////////////////////////////////////Code////////////////////////////////////////////////////////////////////////
var starfm = function(modis, l8){
//Preliminary filtering of MODIS and Landsat
var filt_mod = modis.filterDate(date_begin, date_end);
var filt_l8 = l8.filterDate(date_begin, date_end)
.filterBounds(bounds);
//add bounds to subset area
var subset_bounds = bounds.transform('EPSG:4326', 30).bounds().getInfo();
// get rid of bad pixels but keep metadata date information
var removeBadObservations = function(image){
var valid_data_mask = ee.Image(image).select('pixel_qa').bitwiseAnd(2).neq(0);
var numberBandsHaveData =
image.mask().reduce(ee.Reducer.sum());
var allOrNoBandsHaveData =
numberBandsHaveData.eq(0).or(numberBandsHaveData.gte(9));
var allBandsHaveData = allOrNoBandsHaveData;
//Make sure no band is just under zero
var allBandsGT = image.reduce(ee.Reducer.min()).gt(-0.001);
var result = ee.Image(image).mask(image.mask().and(valid_data_mask).and(allBandsHaveData).and(allBandsGT));
return result.copyProperties(ee.Image(image),['system:time_start']);
};
//NDVI functions for Landsat and MODIS
var getNDVI_mod = function(image){
return image
.addBands(image.normalizedDifference(['sur_refl_b02','sur_refl_b01']).multiply(10000).rename('NDVI'));};
var getNDVI_l8= function(image){
var ndvi = ee.Image(image).normalizedDifference(['B5','B4']);
return ndvi.copyProperties(ee.Image(image),['system:time_start']);
};
var filt2_l8= filt_l8.filterBounds(subset_bounds).aside(print).map(removeBadObservations).map(getNDVI_l8);
// update mask for different areas
var subset_mask = ee.Image().byte().paint(geometry4, "id").add(1);
var filtered_modis = filt_mod.filterBounds(subset_bounds).aside(print).map(getNDVI_mod);
// Pull out the date:
var extract_modis_date = function(row) {
var d = ee.Date(row.get('system:time_start'));
var d2 = ee.Date.fromYMD(d.get('year'), d.get('month'), d.get('day'));
var result = ee.Feature(null, {'date': d2});
result = result.set({'date': d2});
return result;
};
var getQABits = function(image, start, end, newName) {
//// Compute the bits we need to extract.
var pattern = 0;
for (var i = start; i <= end; i++) {
pattern += Math.pow(2, i);
}
//// Return a single band image of the extracted QA bits, giving the band a new name.
return image.select([0], [newName])
.bitwiseAnd(pattern)
.rightShift(start); };
print(filtered_modis);
filtered_modis = filtered_modis.map(function(image){
var quality = getQABits(image.select(2), 4, 5, 'QAMask');
quality = quality.eq(3).not();
return image.clip(subset_bounds).mask(image.mask().multiply(subset_mask).multiply(quality));
});
filtered_modis = filtered_modis.select('NDVI'); //Take only NDVI band
var modis_multiband = ee.Image(filtered_modis.filterDate(date_begin, date_end).iterate( function(x, modis_multiband) {
return ee.Image(modis_multiband).addBands(ee.Image(x));
}, filtered_modis.first()));
var dates_modis = filtered_modis.map(extract_modis_date);
print(dates_modis.getInfo());
var filt2_l8_ndvi = filt2_l8.map(function(image) {
return ee.Image(image)
.clip(subset_bounds)
.mask(ee.Image(image).mask().multiply(subset_mask));
});
//use this to choose the range of days, and check for overlap
var day_expand = 1;
var reduceLandsatNDVI = function(MODISdate) {
MODISdate = ee.Date(MODISdate.get('date'));
var ndvi_subset = ee.ImageCollection(filt2_l8_ndvi).filterDate( MODISdate,
MODISdate.advance(day_expand, 'day') );
ndvi_subset = ndvi_subset.map(function (image) {
var diff = MODISdate.difference(ee.Date(ee.Image(image).get('system:time_start')), 'day').abs();
return ee.Image(image).set('diff', diff);
});
ndvi_subset = ndvi_subset.sort('diff');
var ndvi_first = ndvi_subset.reduce('first');
var ndvi_mean = ndvi_subset.reduce('mean');
return ee.Algorithms.If(
ndvi_first.bandNames(),
ndvi_first.eq(0).multiply(ndvi_mean).add(ndvi_first),
ee.Image(0)
);
};
var extract_landsat_date = function(MODISdate) {
MODISdate = ee.Date(MODISdate.get('date'));
var ndvi_subset =
ee.ImageCollection(filt2_l8_ndvi).filterDate( MODISdate,
MODISdate.advance(day_expand, 'day') );
ndvi_subset = ndvi_subset.map(function (image) {
var diff = MODISdate.difference(ee.Date(ee.Image(image).get('system:time_start')), 'day').abs();
return ee.Image(image).set('diff', diff);
});
ndvi_subset = ndvi_subset.sort('diff');
var d = ndvi_subset.aggregate_first('system:time_start');
var count = ndvi_subset.aggregate_count('system:time_start');
d = ee.Algorithms.If(
ee.Number(count).gt(0),
ee.Date(d),
ee.Date('1971-01-01')
);
d = ee.Date(d);
var d2 = ee.Date.fromYMD(d.get('year'), d.get('month'),
d.get('day'));
var result = ee.Feature(null, {'LSdate': d2, 'MODISdate':
MODISdate, 'CountLSScenes': count});
result = result.set({'LSdate': d2, 'MODISdate': MODISdate,
'CountLSScenes': count});
return result;
};
var ls_collection = dates_modis.map(reduceLandsatNDVI);
print(ls_collection,'ls collection');
var dates_landsat = dates_modis.map(extract_landsat_date);
Export.table(dates_landsat, csv_title);
var ls_multiband = ls_collection.iterate( function(x,
ls_multiband)
{ return ee.Image(ls_multiband).addBands(ee.Image(x));
}, ls_collection.first());
ls_multiband = ee.Image(ls_multiband).multiply(10000).int16();
ls_multiband = ls_multiband.mask(ls_multiband.mask().multiply(ls_multiband.neq(0)));
//remove repeated first layer
var ls_multiband2=ee.Image(ls_multiband.slice(1))
var modis_multiband2=ee.Image(modis_multiband.slice(1))
Export.image.toDrive({
image: modis_multiband2,
description: mod_title,
crs:'EPSG:4326 ',
region:region,
scale:30
});
Export.image.toDrive({
image: ls_multiband2,
description: ls_title,
crs:'EPSG:4326',
region:region,
scale:30
});
return 'Done!'
}
var running = starfm(modis,l8)
print(running)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

How do i get this code to copy only the rows that match my object matching criteria? currently if copies every row

Currently this code copies every row and not the ones that match my criteria
I had some issues getting it to loop. Hence the loggers.
I'm quite new to this.
function searchAnotherSheetAndReturnRows(){
Logger.clear()
var tss = SpreadsheetApp.openById('1dX5MMLXGsG_S_KzRhOcquOp00VhzRBSlTCkyw'); // tss = target spreadsheet
var ts = tss.getSheetByName('Sheet1'); // ts = target sheet
var sss = SpreadsheetApp.openById('1ImDswr6ADS7t4HKIFHpntykN2LS7Mmd-cls34'); // sss = source spreadsheet
var ss = sss.getSheetByName('Page1'); // ss = source sheet
var tslast_row = ts.getLastRow();
var i=0;
Logger.log(i)
for (var i = 1; i < tslast_row; i++) {
Logger.log(i)
Logger.log(tslast_row);
var ssSearch1 = ss.getRange(2,1).getValue();
Logger.log(ssSearch1);
var tsSearch1 = ts.getRange(i,1).getValue();
Logger.log(tsSearch1);
if (ssSearch1 == tsSearch1); {
var tsSearch1Range = ts.getRange(i,1,1,7);
Logger.log(tsSearch1Range);
var range2Copy = tsSearch1Range.getValues();// Copies data from root sheet
Logger.log(range2Copy);
var last_row = ss.getLastRow();
Logger.log(last_row);
var last_row = last_row+1;
Logger.log(last_row);
ss.getRange(last_row,1,1,7).setValues(range2Copy);// Adds root sheet data to target
}
}
}
It's really hard to figure out what you're trying to do. So here's an example that will hopefully help you a little. The job of this function is to copy rows in the AlaskanWilderness that contain GOLD to MyPocket. (Names of Sheets)
function moveGoldFromAlaskanWildernessToMyPocket() {
var tss=SpreadsheetApp.openById('id');
var ts=tss.getSheetByName('MyPocket');
var sss=SpreadsheetApp.openById('id');
var ss=sss.getSheetByName('AlaskanWildernes');
var sr=ss.getDataRange()
var sd=sr.getValues();
var criteria='GOLD';
for (var i=1;i<sd.length;i++) {//skip header
for(var j=0;j<sd[i].length;i++) {
if (sd[i][j]=='GOLD'); {
ss.appendRow(sd[i]);
}
}
}
}
sheet.appendRow
range.getValues

Set the sourceRange of Data Validation to an array of values

I'm creating a social media outreach tracker. I want to create a drop-down list of the contact name. The problem is that I have two sources of names on two different sheets.
I wrote a script that pulls the names from the two different sources and combines them to a single array.
I was hoping to set the source range as that array.
Here is my code:
function setDataValid_(range, sourceRange) {
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(sourceRange, true)
.build();
range.setDataValidation(rule);
}
function onEdit() {
var auditionsSheet = SpreadsheetApp.getActiveSpreadsheet();
var castingDirectorsTab = auditionsSheet.getSheetByName("Casting Directors");
var contactsTab = auditionsSheet.getSheetByName("Contacts");
var socialMediaOutreachTab = auditionsSheet.getSheetByName("Social Media Outreach");
var lastRowCD = castingDirectorsTab.getLastRow();
var lastRowContacts = contactsTab.getLastRow();
var activeCell = socialMediaOutreachTab.getActiveCell();
var activeColumn = activeCell.getColumn();
// get data
var castingDirectorNameData = castingDirectorsTab.getRange(2, 1, lastRowCD, 1).getValues();
var contactNameData = contactsTab.getRange(2, 1, lastRowContacts, 1).getValues();
//get name data to a single arrays
var castingDirectorName = [];
castingDirectorNameData.forEach(function(yr) {
castingDirectorName.push(yr[0]);
});
var contactName = [];
contactNameData.forEach(function(yr) {
contactName.push(yr[0]);
});
// get rid of the empty bits in the arrays
for (var x = castingDirectorName.length-1; x > 0; x--) {
if ( castingDirectorName[x][0] === undefined ) {
castingDirectorName.splice( x, 1 )
}
}
for (var x = contactName.length-1; x > 0; x--) {
if ( contactName[x][0] === undefined ) {
contactName.splice( x, 1 )
}
}
//combine two data sources for data validation
var combinedNames = [];
combinedNames.push(castingDirectorName + contactName);
Logger.log (combinedNames);
Logger.log( typeof combinedNames);
// data validation set up and build
if (activeColumn == 1 && auditionsSheet.getName() == "Social Media Outreach") {
var range = auditionsSheet.getRange(activeCell.getRow(), activeColumn +1);
var sourceRange = combinedNames;
setDataValid_(range, sourceRange)
}
}
When I enter a date in Col A on Social Media Outreach, nothing happens in Col 2.
I was using an existing working nested data validation script I have but the sourceRange pulls from a sheet based on the value in the active cell. Here is that code:
function setDataValid_(range, sourceRange) {
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(sourceRange, true)
.build();
range.setDataValidation(rule);
}
function onEdit() {
var aSheet = SpreadsheetApp.getActiveSheet();
var aCell = aSheet.getActiveCell();
var aColumn = aCell.getColumn();
// data validation for Auditions Tab Projet Type to Project Details
if (aColumn == 9 && aSheet.getName() == 'Auditions') {
var range = aSheet.getRange(aCell.getRow(), aColumn + 1);
var sourceRange = SpreadsheetApp.getActiveSpreadsheet().getRangeByName('RefTables!' + aCell.getValue())
setDataValid_(range, sourceRange)
}
}
For this script when I select from the data validation drop-down, a new data validation comes up in the next col with the appropriate secondary data validation.
So the question is, can the source range be set to an array or do I need to put the names back into my sheet to reference a la the second script.
I've looked through the documentation and searched and can't find an answer. I'm relatively new to GAS and am not sure of all the inner workings of the data validation builder.

Enhancing Performance in Student Info App

I've built a simple Student Information platform using Google Sheets. It allows the user to query, update and create new student info on a user interface. Please refer to this sheet to see how it works.
The functions to Refresh/Update/Save are inside the Actions button on a menu bar. Everything seems to work well however when the number of records increases, say above 100 records, all the functions slow down and it gets extremely slow with 200+ records.
Appreciate if anyone could help to take a look at the scripts as I suspect they need to be optimized.
Many thanks in advance!
function UpdateDataIntoMaster() { //This script is used in the SAVE button in UPDATE sheet)
/*Get data from UPDATE Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheet = ss.getSheetByName('UPDATE');
var range = sheet.getRange("D30:AE30"); //All data transposed into this line. MUST be updated if more fields are added into the Data sheet
var values = range.getValues();
var rangeForKey = sheet.getRange("D30") //Student Name is used as the
key identifier
var keyValue = rangeForKey.getValue();
/*Pass in keyValue(identifier = Student Name)
and all data in the function below in order
to update master data sheet*/
updDbase(keyValue,values);
function updDbase(keyValue,values) {
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY")
var sheet = ss.getSheetByName('Data');
var data = sheet.getDataRange().getValues();
var noOfRow = values.length
var noOfCol = values[0].length
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = ss.getSheetByName("Data").getRange(i+1,1).getValue(); //Get the Student Name from Data sheet
if (keyData == keyValue) {
// for (var j=0; j < data[i].length; j++) { // this is going through all the cell of a row
var row = Number(i)+1;
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Update Information","Are you sure you want to update the student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES)
{
var sheets = ss.getSheetByName("Data").getRange(row,1,noOfRow,noOfCol).setValues(values);
}//If response == YES
}
}
}
}
function CreateNew() {
/*Get data from Inquiry Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheetNew = ss.getSheetByName('Create New');
var range = sheetNew.getRange("D30:AZE30"); //All data transposed into
this line
var values = range.getValues();
var rangeForKey = sheetNew.getRange("E30") //Using Student ID as key identifier
var keyValue = rangeForKey.getValue();
var noOfRow = values.length
var noOfCol = values[0].length
var sheetData = ss.getSheetByName('Data');
var lastRow = sheetData.getLastRow();
var data = sheetData.getDataRange().getValues();
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = sheetData.getRange(i+1,2).getValue(); //Get the Student ID from Data sheet
if (keyData == keyValue) {
AlertBox();//If Student ID is found, to prompt Student ID already
exist
return;
} //If
} //For
/*Confirming with user whether to proceed to create new entry*/
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Create New Record","Are you sure you want to
create new student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES){
if (keyValue == ""){
var response = sh.alert("Create New Record","Unable to proceed
because Student ID is empty", sh.ButtonSet.OK);
return;}
else {
//var response = sh.alert("Create New Record","Unable to
proceed because Student ID is empty", sh.ButtonSet.OK);
var sheets =
sheetData.getRange(lastRow+1,1,1,noOfCol).setValues(values)
}
}//If
}
function EditStudentInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inquiry");
//var ss = SpreadsheetApp.getActive();
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
}
function EditContent() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Update");
var rangeContentCol1 = s.getRange("E3:E23");
var CopyContentCol1 = s.getRange("E3:E23").getValues();
var rangeContentCol2 = s.getRange("I3:I23");
var CopyContentCol2 = s.getRange("I3:I23").getValues();
rangeContentCol1.clearContent();
rangeContentCol2.clearContent();
var PasteContentCol1 =
s.getRange("E3:E23").setValues(CopyContentCol1);
var PasteContentCol2 = s.getRange("I3:I23").setValues(CopyContentCol2);
}
A common performance mistake people with Apps Script is doing the .getRange().getValues() within their for loops. Performance-wise these get and set calls are quite expensive.
Lucky the fix for this is quite easy - get all the data at once first, then loops through it. You actually do this already, sort of. In your script you get the whole data range, but then only use a part of the data and instead do another getValues call. I've updated the two areas in your script that had getRange() calls in a for loop --> var keyData = data[i][0];
function UpdateDataIntoMaster() { //This script is used in the SAVE button in UPDATE sheet)
/*Get data from UPDATE Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheet = ss.getSheetByName('UPDATE');
var range = sheet.getRange("D30:AE30"); //All data transposed into this line. MUST be updated if more fields are added into the Data sheet
var values = range.getValues();
var rangeForKey = sheet.getRange("D30") //Student Name is used as the
key identifier
var keyValue = rangeForKey.getValue();
/*Pass in keyValue(identifier = Student Name)
and all data in the function below in order
to update master data sheet*/
updDbase(keyValue,values);
function updDbase(keyValue,values) {
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY")
var sheet = ss.getSheetByName('Data');
var data = sheet.getDataRange().getValues();
var noOfRow = values.length
var noOfCol = values[0].length
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = data[i][0]; //Use the data that is already loaded.
if (keyData == keyValue) {
// for (var j=0; j < data[i].length; j++) { // this is going through all the cell of a row
var row = Number(i)+1;
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Update Information","Are you sure you want to update the student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES)
{
var sheets = ss.getSheetByName("Data").getRange(row,1,noOfRow,noOfCol).setValues(values);
}//If response == YES
}
}
}
}
function CreateNew() {
/*Get data from Inquiry Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheetNew = ss.getSheetByName('Create New');
var range = sheetNew.getRange("D30:AZE30"); //All data transposed into
this line
var values = range.getValues();
var rangeForKey = sheetNew.getRange("E30") //Using Student ID as key identifier
var keyValue = rangeForKey.getValue();
var noOfRow = values.length
var noOfCol = values[0].length
var sheetData = ss.getSheetByName('Data');
var lastRow = sheetData.getLastRow();
var data = sheetData.getDataRange().getValues();
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = data[i][0]; //Use the data that is already loaded.
if (keyData == keyValue) {
AlertBox();//If Student ID is found, to prompt Student ID already
exist
return;
} //If
} //For
/*Confirming with user whether to proceed to create new entry*/
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Create New Record","Are you sure you want to
create new student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES){
if (keyValue == ""){
var response = sh.alert("Create New Record","Unable to proceed
because Student ID is empty", sh.ButtonSet.OK);
return;}
else {
//var response = sh.alert("Create New Record","Unable to
proceed because Student ID is empty", sh.ButtonSet.OK);
var sheets =
sheetData.getRange(lastRow+1,1,1,noOfCol).setValues(values)
}
}//If
}
function EditStudentInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inquiry");
//var ss = SpreadsheetApp.getActive();
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
}
function EditContent() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Update");
var rangeContentCol1 = s.getRange("E3:E23");
var CopyContentCol1 = s.getRange("E3:E23").getValues();
var rangeContentCol2 = s.getRange("I3:I23");
var CopyContentCol2 = s.getRange("I3:I23").getValues();
rangeContentCol1.clearContent();
rangeContentCol2.clearContent();
var PasteContentCol1 =
s.getRange("E3:E23").setValues(CopyContentCol1);
var PasteContentCol2 = s.getRange("I3:I23").setValues(CopyContentCol2);
}
Give this a test and let me know if it helps!

Updating Panel with new values in GAS UI

I have a huge spreadsheet matrix, from which I create a long list of check boxes. The users then select different abilities, press search. The code the cross-checks with the database spreadsheet, returning names of the persons who has those abilities.
I need to update the "rightPanel" with the results of my search. But i simple can't figure out how to - if at all posible - update a panel in my UI..
var dataSSkey = 'sheetID'; //datasheet ID
var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte');
var groupsArray = [[],[],[],[]];
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues();
var numberGroups
var app = UiApp.createApplication().setTitle('Find Consultant');
var panel = app.createVerticalPanel();
var leftPanel = app.createVerticalPanel().setWidth(450);
var rightPanel = app.createVerticalPanel().setWidth(450);
var grid = app.createGrid(1, 2).setId('myGrid')
var outputArray = []; //to store output from search
var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching
var numberPositive = 0; //number of consultants matching
function doGet() {
buildGroupsArray()
addCheckBoxesToUI()
var scrollPanel = app.createScrollPanel().setHeight(460);
//Search button
var searchButton = app.createButton('Search');
var clickHandler = app.createServerClickHandler("respondToSearch");
searchButton.addClickHandler(clickHandler);
clickHandler.addCallbackElement(panel);
var spacerImage = app.createImage("http://www.bi..ge.jpg").setHeight(3);
scrollPanel.add(panel);
rightPanel.add(app.createLabel('resultat her'));
leftPanel.add(scrollPanel);
leftPanel.add(spacerImage);
leftPanel.add(searchButton);
grid.setWidget(0, 0, leftPanel)
grid.setWidget(0, 1, rightPanel);
app.add(grid);
return app;
}
function respondToSearch(e){
var numberLogged = 0;
//define firstEmpty
var firstEmpty = "A"+lastRow;
if(lastRow !== 1){
firstEmpty = "A"+(lastRow+1);
};
//find selected competencies --> store in array + count competencies
for(i = 1; i <= lastRow; i++){
if (e.parameter["Checkbox"+i] == "true") {
var value = e.parameter["CheckboxValue"+i];
outputArray[numberLogged] = value;
numberLogged++;
}
}
for(i = 2; i <= lastColumn; i++){
var numberCorrect = 0;
//Run through rows according to content of output from selection
for(j in outputArray){
//Check if consultant own selected competency
if(dataArray[outputArray[j]][i] == "x"){
numberCorrect++; //if consultant owns selected competency then count
}
}
//if consultant owns all competencies, then add name and folder-id to array
if(numberCorrect == numberLogged){
positiveList[0][numberPositive] = dataArray[1][i]; //Add consultant name
positiveList[1][numberPositive] = dataArray[2][i]; //Add consultant-folder ID
numberPositive++ //count the number of consultants that own all competencies
}
}
for(j in positiveList[0]){
var name = positiveList[0][j];
var id = positiveList[1][j];
Logger.log(name);
Logger.log(id)
var anchor = app.createAnchor(name,'https://ww......folderviewid='+id);
rightPanel.add(anchor)
}
return app;
}
I don't really understand the problem you have...
In your handler function you only have to use app=UiApp.getActiveApplication() and from there populate the panel exactly the same way you did it in the doGet() function, ending with a return app; that will actually update the current Ui.
There are dozens of examples all around... did I misunderstand something in your question ?
Edit : following your comment.
I suppose you defined your variables outside of the doGet function hoping they will become global and so available to all the functions in your script but this is not going to work. Global variables in Google Apps script can't be updated by functions.
I would strongly recommend that you create app and panels in the doGet function and give them an ID so that you can get them back and update their values (or content) from the handler functions.
Here is a re-written version of your code (didn't test)
: (some parts are not reproduced (see //...)
var dataSSkey = 'sheetID'; //datasheet ID
var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte');
var groupsArray = [[],[],[],[]];
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues();
var numberGroups
var outputArray = []; //to store output from search
var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching
var numberPositive = 0; //number of consultants matching
function doGet() {
var app = UiApp.createApplication().setTitle('Find Consultant');
var panel = app.createVerticalPanel();
var leftPanel = app.createVerticalPanel().setWidth(450).setId('leftPanel');
var rightPanel = app.createVerticalPanel().setWidth(450).setId('rightPanel');;
var grid = app.createGrid(1, 2).setId('myGrid')
buildGroupsArray(app); // in this function get app as parameter or use UiApp.getActiveApplication();
addCheckBoxesToUI(app);// in this function get app as parameter or use UiApp.getActiveApplication();
var scrollPanel = app.createScrollPanel().setHeight(460);
//...
//...
return app;
}
function respondToSearch(e){
//...
//...
var app = UiApp.getActiveApplication();
var rightPanel = app.getElementById('rightPanel');
for(j in positiveList[0]){
var name = positiveList[0][j];
var id = positiveList[1][j];
Logger.log(name);
Logger.log(id)
var anchor = app.createAnchor(name,'https://ww......folderviewid='+id);
rightPanel.add(anchor)
}
return app;
}

Resources