Reputation: 9027
I'd like to add buttons to specific cells in Google docs spreadsheet. The apps script UI documentation talks about how to add a new panel, but it's not clear how UI in that panel could be attached to specific rows or cells.
Is it possible to add UI to particular cells, or are we limited to adding new panels?
Upvotes: 73
Views: 217515
Reputation: 1208
I have been unable to attach drawings to cells. Instead, I use a visual illusion to make a cell look similar to a button, then use onSelectionChange()
to run a script when that cell is clicked. You can't click twice in a row, though. You have to click outside the cell and back in again.
For the visual 3D shading illusion, I use thick colored borders. I give the "button" cell:
If I need multiple buttons next to each other, I put an extra column between them or it looks wrong to me because the border between them can only have one color. It's a bit annoying to work with. Here they are without an extra column:
Here they are with an extra column:
App script can't listen for someone to click on a cell. It can listen for someone changing which cell is selected, though. When you do that, it's important to check that the click is in the right cell:
function onSelectionChange(event) {
// Act based on text content
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveCell();
var text = activeCell.getValue();
console.log("text", text); // for the debugger
if (text === "thing 1") { function1(); }
else if (text === "thing 2") { function2(); }
}
I had a bunch of these "buttons" and I found it annoying to interact with those cells when I wanted to edit them, so I also used a "property" to activate and deactivate that interaction:
function onSelectionChange(event) {
var isActive = PropertiesService.getScriptProperties().getProperty("active")
console.log("Cells are active", JSON.stringify(isActive));
if ( isActive !== "true" ) { return; }
// Act based on text content
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveCell();
var text = activeCell.getValue();
console.log("text", text); // for the debugger
if (text === "thing 1") { function1(); }
else if (text === "thing 2") { function2(); }
}
function activate() {
// I think these get saved as strings even if you give
// a boolean value, so I just gave a string
PropertiesService.getScriptProperties().setProperty("active", "true");
console.log("After activated", JSON.stringify(PropertiesService.getScriptProperties().getProperty("active")));
}
function deactivate() {
PropertiesService.getScriptProperties().setProperty("active", "false");
console.log("After deactivated", JSON.stringify(PropertiesService.getScriptProperties().getProperty("active")));
}
I did use drawings as buttons with the activate
and deactivate
functions instead of cells because that was less annoying to program. I did have a lot of cell-type "buttons", so it was worth it.
I also changed the colors of the cells when I activated and deactivated them. This part is a bit untested. My code was much more specific to my situation. I was coloring bigger ranges and using different colors.
function activate() {
PropertiesService.getScriptProperties().setProperty("active", "true");
setStyle("#cccccc", "#000000", "A1");
}
function deactivate() {
PropertiesService.getScriptProperties().setProperty("active", "false");
setStyle("#b7b7b7", "#999999", "A1"); // Maybe not enough contrast for some people
}
function setStyle(backgroundColor, fontColor, cellAddress) {
var range = SpreadsheetApp.getActiveSheet().getRange(cellAddress);
range.setBackground(backgroundColor);
range.setFontColor(fontColor);
}
Upvotes: 0
Reputation: 136
There is a silly trick to do something that might help you :
You can make the drawing object as tall as your sheet (To appear to every row in the sheet).
You can make the script affects the current cell value by the following code:
SpreadsheetApp.getActiveSpreadsheet().getActiveCell().setValue(cellValue);
Upvotes: 0
Reputation: 50383
Use checkboxes(say, in F1) instead of buttons/Images. This is a intermediate to a full ui inside cells. Then hook your function, that is supposed to run on button click to onEdit()
trigger function.
function onEdit(e){
const rg = e.range;
if(rg.getA1Notation() === "F1" && rg.isChecked() && rg.getSheet().getName() === "Sheet1"){
callFunctionAttachedToImage();
rg.uncheck();
}
}
Upvotes: 7
Reputation: 20852
There seems to be no way to place buttons (drawings, images) within cells in a way that would allow them to be linked to Apps Script functions.
This being said, there are some things that you can indeed do:
You can place images within cells using IMAGE(URL)
, but they cannot be linked to Apps Script functions.
You can place images within cells and link them to URLs using:
=HYPERLINK("http://example.com"; IMAGE("http://example.com/myimage.png"; 1))
You can create drawings as described in the answer of @Eduardo and they can be linked to Apps Script functions, but they will be stand-alone items that float freely "above" the spreadsheet and cannot be positioned in cells. They cannot be copied from cell to cell and they do not have a row or col position that the script function could read.
Upvotes: 67
Reputation: 324
Buttons can be added to frozen rows as images. Assigning a function within the attached script to the button makes it possible to run the function. The comment which says you can not is of course a very old comment, possibly things have changed now.
Upvotes: 4
Reputation: 22824
The apps UI only works for panels.
The best you can do is to draw a button yourself and put that into your spreadsheet. Than you can add a macro to it.
Go into "Insert > Drawing...", Draw a button and add it to the spreadsheet. Than click it and click "assign Macro...", then insert the name of the function you wish to execute there. The function must be defined in a script in the spreadsheet.
Alternatively you can also draw the button somewhere else and insert it as an image.
More info: https://developers.google.com/apps-script/guides/menus
Upvotes: 125