Can you set the mergedCells property in Kendo UI for jQuery ooxml.Workbook.sheets without range name? - kendo-ui

I am having an issue merging cells that are in an existing sheet in a workbook. My attempt to use mergedCells after the sheet is created has presented a roadblock, I can't seem to get the range name in string format as documented for the mergedCells option in Workbook.sheet:
mergedCells: ["A6:A8"]
All I have are indexes of the cells.
I have the logic to determine which cells' indexes I want to merge, but only the indexes. I can't figure out a way to get the range in an Excel cell name/string like "A1". In the following example, ignoring how I got the index values, I can't merge the cells based on index where indexA is the column and indexB1 and indexB2 are rows.
let indexA = 0;
let indexB1 = 5;
let indexB2 = 7;
sheet.mergedCells = [[{indexA, indexB1},{indexA,indexB2}]]
I have attached a picture of the types of cells I want to merge that are in my workbook, my loop first hits A6 through A8 and determines the indexes are to be merged because all the cells' values equal "Boat". Any help is appreciated, and I will try to provide more detail if needed, but it is difficult to provide much more because of the nature of the system I am on.
Thanks in advance.format of workbook

So you have the R1C1 notation of the cells you need to merge? If so, following the suggestion in this thread you can generate the range in A1 notation - example:
function columnName(index) {
var cname = String.fromCharCode(65 + ((index - 1) % 26));
if (index > 26)
cname = String.fromCharCode(64 + (index - 1) / 26) + cname;
return cname;
}
var r1 = 2;
var c1 = 3;
var r2 = 4;
var c2 = 5;
var rangeAsString = `${columnName(c1)}${r1}:${columnName(c2)}${r2}`;
var workbook = new kendo.ooxml.Workbook({
sheets: [{
mergedCells: [rangeAsString],
rows: [
{ cells: [ { value: "Document Title" } ] },
{ cells: [ { value: 22 }, { value: 33 }, { value: 44 }, {value: 55} ] }
]
}]
});
kendo.saveAs({
dataURI: workbook.toDataURL(),
fileName: "Test.xlsx"
});

Related

Google script pushing data from one tab to another while retaining data validation

I have the following google apps script. It functions to look in my PENDING-IP tab and check the status (column G). If the status is "Screened - Ready for Review," then it moves the entire row of data to the SCREENED - READY FOR REVIEW tab.
My problem is this - the data in columns L, M, and N of the PENDING tab is a checkbox, but when it pushes it to the SCREENED tab, it changes it to TRUE or FALSE. Is there a way to modify my script to push the data with validation to retain the checkboxes? Thank you!
function screened() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('PENDING-IP'); //source sheet
var testrange = sheet.getRange('G:G'); //range to check
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('SCREENED - READY FOR REVIEW'); //destination sheet
var data = [];
var j =[];
//Condition check in G:G; If true copy the same row to data array
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Screened - Ready for Review') {
data.push.apply(data,sheet.getRange(i+1,1,1,25).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
//Delete matched rows in the source sheet
for (i=0;i<j.length;i++){
var k = j[i]+1;
sheet.deleteRow(k);
//Alter j to account for deleted rows
if (!(i == j.length-1)) {
j[i+1] = j[i+1]-i-1;
}
}
}
Try this
I haven't actually tested this except in a simpler situation
function screened() {
var ss=SpreadsheetApp.getActive();
var sheet=ss.getSheetByName('PENDING-IP');
var testrange=sheet.getRange(1,7,sheet.getLastRow(),1);
var testvalue=testrange.getValues();
var valids=testrange.getDataValidations();
var csh = ss.getSheetByName('SCREENED - READY FOR REVIEW'); //destination sheet
var data = [];
var valid = [];
var j =[];
var d=0;
for (var i=0;i<testvalue.length;i++) {
if (testvalue[i][0] == 'Screened - Ready for Review') {
data.push(sheet.getRange(i+1-d,1,1,25).getValues());//I am not sure but I could see having to put [0] at the end here
valid.push(sheet.getRange(i+1-d,1,1,sh.getLastColumn()).getDataValidations());//I am not sure but I could see having to put [0] at the end here
sheet.deleteRow(i+1-d++);//this should delete matching rows
}
}
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(valid);
}
What I've found is that you can treat the validations the same way you treat the data by replacing getValues() with getDataValidations() and setValues() with setValidations();

DC.js - Select Menu as a filter for Composite charts

My dataset is similar to this.
name,code,proc,subP,date,m,a,b,o,t
BW,1333,29,1,2015-12-29 02:30:00,10,0,0,0,10
BW,1333,29,1,2015-12-29 12:00:00,25,0,0,0,25
BW,1333,29,1,2015-12-30 12:00:00,26,0,0,0,26
BW,1333,29,2,2015-12-31 12:00:00,27,0,0,0,27
BW,1333,29,2,2016-01-01 12:00:00,26.1,4.9,1.8,0,32.8
BW,1333,29,2,2016-01-02 12:00:00,26.4,4.9,1.9,0,33.2
BW,1333,29,2,2016-01-03 12:00:00,26.2,4.9,1.9,0,33
...
NS,1212,11,1,2016-07-28 15:30:00,1.6,3.7,4.4,0,9.7
NS,1212,11,1,2016-07-29 12:00:00,17.4,2.3,0,0,19.7
NS,1212,11,1,2016-07-30 12:00:00,21,5,14.1,0,40.1
NS,1212,11,2,2016-07-31 11:12:00,18.1,3.5,6.1,0,27.7
NS,1212,11,2,2016-07-31 12:00:00,0.1,0.2,0.2,0,0.5
NS,1212,11,2,2016-08-01 12:00:00,0.1,2.7,2.6,0,5.4
I'm using a composite line chart to represent this data.
I'm using selectMenu to filter 'BW' and 'NS' records. But the composite chart remains unchanged when I use selectmenu.
I split the data into two seperate files (one with 'BW' records and the other with 'NS' records) to try to implement the data selection functionality provided in dc.js Series Chart example . That didnt work either.
Here is a fiddle with one of the charts.
Ultimately, I would like to filter multiple charts(composite, series and bubble) by 'BW' and 'NS' records with or without a select menu.
How can I implement this?
The problem isn't with your selectMenu or your composite chart, it's with the way you are reducing data.
The first parameter to group.reduce() is the add function, the second parameter is the remove function, and the final one is the initialize function.
You usually don't want to set p directly from v as you are doing:
var grp = dim.group().reduce(
function(p,v){
p.m = +v.m;
p.a = +v.a;
p.b = +v.b;
return p;
},
function(p,v){
p.m = +v.m;
p.a = +v.a;
p.b = +v.b;
return p;
},
function(){return {m:0, a:0, b:0}; });
That will only work if every key is perfectly unique and no two items ever fall in the same bin.
And you almost never want to set p from v in the remove function. That will prevent anything from ever being removed.
Instead, add and subtract the values like so:
var grp = dim.group().reduce(
function(p,v){
p.m = p.m + +v.m;
p.a = p.a + +v.a;
p.b = p.b + +v.b;
return p;
},
function(p,v){
p.m = p.m - +v.m;
p.a = p.a - +v.a;
p.b = p.b - +v.b;
return p;
},
function(){return {m:0, a:0, b:0}; });
Here's a working fork of your fiddle.

Copying rendered value instead of the data value

I use Handsontable and in one column, the data type is an integer that is an index of a vector of strings v. So, instead of showing the integer index i, I have to show v[i]. I do so by declaring a custom renderer in handsontable:
var annotationTableSettings = {
data: componentAnnotation,
columns: [
{renderer: annotationId2StringRenderer},
...
However, when I copy the value of the cell (Ctrl+c in windows/linux or cmd+c in mac), the integer is copied instead of the rendered value. Does anyone know how to copy the rendered value (I would like to keep the integer data type and the custom renderer).
An example can be seen here: http://leoisl.gitlab.io/DBGWAS_support/full_dataset_visualization_0_4_6/components/comp_2.html
Just copy the first cell of the first line of the first table (in the north panel) - the cell with value "(Phe)CML" and you will copy the value 3, instead of "(Phe)CML" itself.
Thanks in advance!
you can use the beforeCopy hook.
var annotationTableSettings = {
data: componentAnnotation,
beforeCopy: data => {
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].length; j++) {
if (!isNaN(data[i][j])) {
data[i][j] = v[data[i][j]]
}
}
}
}
columns: [
{renderer: annotationId2StringRenderer},
...

Sorting Google Spreadsheet on edit

I am searching for a way to sort my spreadsheet. I have looked around and found the "on edit" function but I am not entirely sure on how to use it. And how does it work with the runtime of only 5 minutes for google scripts, does a cellchange act as a trigger?
I found the following code:
function AutoSortOnEdit() {
var sheetNames = ["testsheet456", "testsheet457", "testsheet458"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
sheetNames.forEach(function(name) {
var sheet = ss.getSheetByName(name);
var range = sheet.getRange(5, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
range.sort({column: 1, ascending: true});
});
Personally i would use this slightly modified version:
function AutoSortOnEdit() {
var sheet = SpreadsheetApp.openById("...").getSheetByName("...");
var range = sheet.getRange(5, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
range.sort({column: 1, ascending: true});
});
Now I want to sort the sheet in alphabetical order sorted by the first row.
My questions are:
Does "ascending" mean that it sorts in alphabetical order?
Where do empty cells land(they should be at the end obviously)?
Does it gets triggered on every change? Can i manipulate to only sort it when Column A gets edited?
Regards Jonny
Edit: In the end i went with my slighlty modified version since onEdit was after all not fitting in the situation.
Yes, ascending is alphabetical. This code looks for only a change in the sheet named Sheet1 and only column A. The function must be named OnEdit (not AutoSortOnEdit).
function onEdit()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetName= sheet.getSheetName();
if(sheetName=="Sheet1"){ //sheet to run on edit
var editRange = sheet.getActiveRange();
var editRow = editRange.getRow();
var editCol = editRange.getColumn();
var lr = sheet.getLastRow()
var range = sheet.getRange("A1:A"+lr);//apply on edit to
var rangeRowStart = range.getRow();
var rangeRowEnd = rangeRowStart + range.getHeight()-1;
var rangeColStart = range.getColumn();
var rangeColEnd = rangeColStart + range.getWidth()-1;
if (editRow >= rangeRowStart && editRow <= rangeRowEnd
&& editCol >= rangeColStart && editCol <= rangeColEnd)
{
var range = sheet.getSheetByName(sheetName).getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());//Assumes header row
range.sort({column: 1, ascending: true});
}}}
Simple event triggers are limited to a 30 second execution time.
onEdit() events must be named simply onEdit() or onEdit(event)
onEdit can take a variable that represents the event that triggered it, that among other things, includes the range that was edited.
Sheet has it's own sort(). If you are trying to sort the entire sheet it is simpler to use that.
function onEdit(event){
if(event.range.getSheet().getName() == "Sheet1" && event.range.getColumn() == 1){//checks to see if the edited range was both on Sheet1 and column 1 (A)
event.range.getSheet().sort(1,true); //sort by first column
// event.range.getSheet().sort(1,false); //decending
}
}
multiple sheets can watched by expanding the conditionals, or aditional if statements.

Is there a way to mass input data validation in google sheets

I'm trying to create a drop down menu with contents based on a another cell in the same row. For example if A1 = 'yes' then the drop down in B2 gives you the options of 'yes' or 'no'. I can do this I have the list data set up and to code works. The problem is I need to do this 155 times in 4 different sheets. Is there a faster way to do this than right clicking and editing the data validation rules for each cell. Here's a link to the test sheet I'm working on :
https://docs.google.com/spreadsheets/d/1rd_Ig_wpof9R_L0IiA1aZ9syO7BWxb6jvBhPqG8Jmm4/edit?usp=sharing
You can set data validation rules with a script, as documented here. Here's a reference for starting with Apps scripts.
I wrote a function that does approximately what you described. It works with the range B3:B157 of the sheet '9th grade' in the current spreadsheet. For each of them, it sets the validation rule to be: a value in the same row, columns B and C of sheet 'List Data'. The line with
....... = listData.getRange(i+3, 2, 1, 2);
will need to be modified if the source range of validation is to be different. Here, the parameters are: starting row, starting column, number of rows, number of columns. So, 2 columns starting with the second, in row numbered i+3.
function setRules() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var grade = ss.getSheetByName('9th Grade');
var listData = ss.getSheetByName('List Data');
var range = grade.getRange('B3:B157');
var rules = range.getDataValidations();
for (var i = 0; i < rules.length; i++) {
var sourceRange = listData.getRange(i+3, 2, 1, 2);
rules[i][0] = SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange).build();
}
range.setDataValidations(rules);
}
I land in this issue for a diferent reason: "Just mass DataValidation copy (or update) in one column". Thanks, to user3717023 that bring me a light.
I hope that helps someone this simplification.
function setRules() {
//select spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var leads = ss.getSheetByName('Leads');
//Select correct Datavalidation
var rangeNewDataValidation = leads.getRange('M2:M2');
var rule = rangeNewDataValidation.getDataValidations();
//Copy (or Update) Datavalidation in a specific (13 or 'M') column
var newRule = rule[0][0].copy();
Logger.log(leads.getMaxRows())
for( var i=3; i <= leads.getMaxRows(); i++){
var range = leads.getRange(i, 13);
range.setDataValidations([[newRule.build()]]);
}
}

Resources