In a Google docs spreadsheet. If cells A1 & A2 are merged, is there a way to confirm they are merged, using google apps script?
There is a merge function in GAS
There seems to be a workaround exploiting the fact that merged cells always return a white background. The code below appears to work for me; I will appreciate it if anyone can confirm.
function testMerged() {
var WHITE = '#ffffff';
var NON_WHITE = '#fffffe';
var range = SpreadsheetApp.getActiveSheet().getDataRange();
range.setBackground(NON_WHITE);
range.getBackgrounds().forEach(function (row, rowNum) {
row.forEach(function (col, colNum) {
if (col === WHITE) { Logger.log('Cell merged at row ' + rowNum + ' col ' + colNum); }
});
});
range.setBackground(WHITE);
}
It's not possible to know that. There's already an issue opened regarding this, but it is quite old and has no activity. You should star it (to keep track of updates and kind of vote for it) and leave a comment to see if you can get some attention.
But what I do when I need to assure merged cells are as I want them is to break everything apart and merge again, just to be sure. Of course, this is not a solution, just an idea that might suit you as well.
Download as HTML: You can download a sheet as HTML, this will include the merged cell info. Not a nice solution, but it works.
Example download url:
docs.google.com/feeds/download/spreadsheets/Export?key=* spreadsheetkey *&exportFormat=html&gid=3
where gid is the sheet gid number. - signin is required via google drive api (see google drive DrEdit Tutorial for details)
Yes, now you can use isPartOfMerge
to check.
And for anyone wants to get the value of merged cell:
var value = (cell.isPartOfMerge() ? cell.getMergedRanges()[0].getCell(1,1) : cell).getValue();
Hope it help.
Found this solution, posted here:
https://code.google.com/p/google-apps-script-issues/issues/detail?id=618
But only works for active range
// This is my function to test the active range is merged or not and return
// true or false by passing active range to it
function ismerge() {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getActiveSheet();
var last_row = sheet.getActiveRange().getLastRow();
var last_col = sheet.getActiveRange().getLastColumn();
Logger.log("Last row: %s", last_row);
var active_row = sheet.getActiveRange().getRow();
var active_col = sheet.getActiveRange().getColumn();
Logger.log("Row: %s", active_row);
if ( (last_row == active_row) && (last_col == active_col) ) {
Logger.log("Cell not merged");
return false;
}
else {
Logger.log("Cell merged");
return true;
}
}
range.isPartOfMerge()
It seems the .isPartOfMerge()
method was implemented (11 sept 2016).
So you can check if a range is merged as such:
function testMerge() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getRange(1,1,2); // example for cells A1 and A2
Logger.log(range.isPartOfMerge());
}
Docs https://developers.google.com/apps-script/reference/spreadsheet/range#ispartofmerge
OLD APPROACH
Posting here another approach that I like more than the accepted answer.
If you try to use GAS to store a value in a cell of a merged range, except the first cell, it will not store it.
As such, we can exploit this and attempt to store the value and check if it was stored, using a function similar to this one:
function isMerged(range){
try {
range.getDataSourceUrl()
} catch (err) {
throw "isMerged function only works with valid GAS Range objects"
}
var sheet = range.getSheet();
var rangeData = range.getValues();
var testValue = "testing merge";
if (rangeData.length == 1 && rangeData[0].length == 1) return false; // we have a single cell. Can't possible be merged :)
if (rangeData.length == 1) {
// We have a single row. Which means we're testing a row with multiple columns
var mainCell=range.getA1Notation().split(":")[0];
var rowNumber= sheet.getRange(mainCell).getRow();
var nextColNumber = sheet.getRange(mainCell).getColumn()+1;
var row = rangeData[0];
var oldValue = row[1]; // for testing purposes, we're chosing the next possible column
sheet.getRange(rowNumber,nextColNumber).setValue(testValue);
if (sheet.getRange(rowNumber,nextColNumber).getValue() !== testValue) {
return true;
} else {
sheet.getRange(rowNumber,nextColNumber).setValue(oldValue);
return false;
};
} else if (rangeData[0].length == 1) {
// We have multiple rows and a single column.
var mainCell=range.getA1Notation().split(":")[0];
var nextRowNumber= sheet.getRange(mainCell).getRow()+1;
var colNumber = sheet.getRange(mainCell).getColumn();
var oldValue = rangeData[1][0]; // for testing purposes, we're chosing the next possible row
sheet.getRange(nextRowNumber,colNumber).setValue(testValue);
if (sheet.getRange(nextRowNumber,colNumber).getValue() !== testValue) {
return true;
} else {
sheet.getRange(nextRowNumber,colNumber).setValue(oldValue);
return false;
};
} else {
// We have multiple rows and multiple columns
var mainCell=range.getA1Notation().split(":")[0];
var nextRowNumber= sheet.getRange(mainCell).getRow()+1;
var nextColNumber = sheet.getRange(mainCell).getColumn()+1;
var oldValue = rangeData[1][1]; // for testing purposes, we're chosing the next possible row and next possible column
sheet.getRange(nextRowNumber,nextColNumber).setValue(testValue);
if (sheet.getRange(nextRowNumber,nextColNumber).getValue() !== testValue) {
return true;
} else {
sheet.getRange(nextRowNumber,nextColNumber).setValue(oldValue);
return false;
};
}
// if none of these checks worked, something's fishy. Either way, return false
return false
}
I've ran a series of quick tests and it returned true
/false
accordingly, but there is a limitation that I didn't have time to cover:
If you had a merged range like "A1:F1"
and you checked the range "A1:G1"
(so, one more column), it will return true
, even if G1 is not part of the merged range - because it checks only the next column using as reference the first bound row/column.