I have a big problem since 2 days, my functiun doesn't work anymore :/
"Service error: Spreadsheets" at "if (cell.isBlank())"
function miseEnForme(){
var classeur = SpreadsheetApp.getActive();
var feuilleAdm = classeur.getSheetByName("SuiviAdministratif");
var lastRow;
for (var row = 3; row < 1000; row++) {
var cell=feuilleAdm.getRange(row,3);
if (cell.isBlank()) {
lastRow =row;
break;
}
}
for (var i =3; i<lastRow;i++){
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="RS" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RP" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RD")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("red");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="C")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("#00ff00");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="O")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("white");
}
}
Is it my fault or Google have change something?
How to solve the problem?
Thanks
Checkout this link. I'm guessing that there's nothing wrong with the code. It's just that Google Servers are trying to entice you into using a more batch oriented approach. For example you could get all of your data with one call to var datA=sheet.getDataRange().getValues(); and then you would have all of your data in a 2 dimensional array. It would be easier for Google servers to handle your process and it would perform much better for you. I'll take a copy of your code and see if I can simplify it for you. Perhaps you could give me an idea of what your data looks like.
I haven't tested this code. If you can share some of your data with me I'll be glad to do so. This should be pretty close though. I tried to follow the same basic approach that you were using so you could figure out what's happening a little easier.
function miseEnForme()
{
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sht = ss.getSheetByName("SuiviAdministratif");
var datrng = sht.getDataRange();
var datA = datrng.getValues();//datA is a 2 dimensional array starts at zero
var lastCol = datrng.getLastColumn();
for(var i=2;i<datA.length;i++)
{
if(datA[1][i] == ("RS" || "RP" || "RD"))
{
sht.getRange(i+1,1,1,lastCol).setBackground('#ff0000');
}
if(datA[1][i] == "C")
{
sht.getRange(i+1,1,1,lastCol).setBackground('#00ff00');
}
if(datA[1][i] == "O")
{
sht.getRange(i+1,1,1,lastCol).setBackground('#ffffff');
}
}
}
As Cooper say, your code is not the problem here.
Otherwise, a little workaround will help you :
function miseEnForme(){
var classeur = SpreadsheetApp.getActive();
var feuilleAdm = classeur.getSheetByName("SuiviAdministratif");
// getLastRow() return the value of the last row used in the sheet
var lastRow = feuilleAdm.getLastRow();
for (var i =3; i<lastRow;i++){
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="RS" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RP" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RD")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("red");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="C")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("#00ff00");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="O")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("white");
}
}
More about the getLastRow method : https://developers.google.com/apps-script/reference/spreadsheet/sheet#getLastRow()
Related
I have a Google sheets with texts in 590 rows. I need to replace multiple words of these texts in other word as a category. For example, I need to find the words "brontolaren minacciaren pettegolezzin maleducaton" and replace them with the word "relazionin". I'm trying to write an apps scripts to do this, and I found a script created by FluffyLlemon that I adapted, and I thought could work for me:
function FindAndReplace() {
var data_range = SpreadsheetApp.getActiveSheet().getDataRange();
var num_rows = data_range.getNumRows();
var num_columns = data_range.getNumColumns();
var find_replace ={
"brontolaren" : "relazionen",
"minacciaren" : "relazionen",
"pettegolezzin" : "relazionen",
"maleducaton" : "relazionen",
"riservatezzan" : "relazionen",
"sottopressionen": "relazionen",
}
Object.keys(find_replace).map(function(find) {
var replace = find_replace[find];
for (var row=1; row <= num_rows; row++) {
for (var col=1; col <= num_columns; col++) {
var value = data_range.getCell(row, col).getValue();
if (data_range.getCell(row, col).getFormula()) {continue;}
try {
value = value.replace(find, replace);
data_range.getCell(row, col).setValue(value);
}
catch (err) {continue;}
}
}
});
}
By executing this code, just the first word is replaced and not the others, and it seems to take a long time and never stop. This is the first time I use apps script... How can I improve the code?
Try it this way:
function FindAndReplace() {
const ss = SpreadsheetApp.getActive();
var rg = ss.getDataRange();
const r = "relazionen";
const f =["brontolaren","minacciaren","pettegolezzin","maleducaton","riservatezzan","sottopressionen"];
f.forEach(n => {
rg.createTextFinder(n).replaceAllWith(r);
});
}
As another approach, in this sample script, the value of search is used as a regex.
Sample script:
function FindAndReplace() {
const search = ["brontolaren", "minacciaren", "pettegolezzin", "maleducaton", "riservatezzan", "sottopressionen"];
const replace = "relazionen";
SpreadsheetApp
.getActiveSheet()
.getDataRange()
.createTextFinder(search.join("|"))
.useRegularExpression(true)
.replaceAllWith(replace);
}
Note:
When several values are replaced with one value, the process cost can be reduced by the above method. But, when several values are replaced with each unique value, this report might be useful. Ref
References:
createTextFinder(findText)
useRegularExpression(useRegEx)
replaceAllWith(replaceText)
I need to get values {nb_conversions":58"} under idgoal=ecommerceAbandonedCart, idgoal=4 and so on , I have tried different ways but unsuccessful, would appreciate it if someone can quickly sort this out for me.
Here is API URL: https://demo.matomo.cloud/?module=API&method=UserCountry.getRegion&idSite=1&period=day&date=yesterday&format=JSON&token_auth=anonymous
Sample Data:
[{"label":"Unknown","nb_uniq_visitors":558,"nb_visits":590,"nb_actions":980,"nb_users":0,"max_actions":14,"sum_visit_length":76439,"bounce_count":408,"nb_visits_converted":45,"goals":{"idgoal=ecommerceAbandonedCart":{"nb_conversions":58,"nb_visits_converted":58,"revenue":16199.299999999997,"items":88},"idgoal=ecommerceOrder":{"nb_conversions":10,"nb_visits_converted":10,"revenue":606.7,"revenue_subtotal":2448,"revenue_tax":0,"revenue_shipping":0,"revenue_discount":22.45,"items":12},"idgoal=4":{"nb_conversions":2,"nb_visits_converted":2,"revenue":2},"idgoal=5":{"nb_conversions":1,"nb_visits_converted":1,"revenue":5},"idgoal=6":{"nb_conversions":2,"nb_visits_converted":2,"revenue":4},"idgoal=7":{"nb_conversions":16,"nb_visits_converted":16,"revenue":16},"idgoal=8":{"nb_conversions":13,"nb_visits_converted":13,"revenue":0},"idgoal=10":{"nb_conversions":1,"nb_visits_converted":1,"revenue":0}},"nb_conversions":45,"revenue":633.7,"region":"xx","country":"xx","country_name":"Unknown","region_name":"Unknown","logo":"plugins\/Morpheus\/icons\/dist\/flags\/xx.png"}]
function Goals() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Goals");
var lastRow = sheet.getLastRow();
var today = sheet.getRange(1,6).getValue().toDateString();
var startDate = sheet.getRange(lastRow,1).getValue();
var now = sheet.getRange(lastRow,1).getValue().toDateString();
var dt = new Date(startDate);
//Logger.log(now);
// Logger.log(today);
//Logger.log(dt);
if( today != now){
var response = UrlFetchApp.fetch("https://demo.matomo.cloud/?module=API&method=UserCountry.getRegion&idSite=1&period=day&date=yesterday&format=JSON&token_auth=anonymous");
var json=response.getContentText();
var dataSet=JSON.parse(json);
for(var i = 0; i < dataSet.length; i++)
{
sheet.getRange(i+lastRow+1,2).setValue([dataSet[i]['label']]);
sheet.getRange(i+lastRow+1,3).setValue([dataSet[i]['nb_visits']]);
sheet.getRange(i+lastRow+1,4).setValue([dataSet[i]['nb_uniq_visitors']]);
sheet.getRange(i+lastRow+1,5).setValue([dataSet[i]['goals']['idgoal=ecommerceAbandonedCart']]);
sheet.getRange(i+lastRow+1,1).setValue(now);
}
dt.setDate(dt.getDate()+1);
lastRow = sheet.getLastRow();
sheet.getRange(lastRow+1,1).setValue(dt);
}
}
Given your sample data, try fetching the keys using Object.keys() and loop them one by one to get all nb_conversions instead of passing the idgoals individually. See below:
Code:
var dataSet = [{"label":"Unknown","nb_uniq_visitors":558,"nb_visits":590,"nb_actions":980,"nb_users":0,"max_actions":14,"sum_visit_length":76439,"bounce_count":408,"nb_visits_converted":45,"goals":{"idgoal=ecommerceAbandonedCart":{"nb_conversions":58,"nb_visits_converted":58,"revenue":16199.299999999997,"items":88},"idgoal=ecommerceOrder":{"nb_conversions":10,"nb_visits_converted":10,"revenue":606.7,"revenue_subtotal":2448,"revenue_tax":0,"revenue_shipping":0,"revenue_discount":22.45,"items":12},"idgoal=4":{"nb_conversions":2,"nb_visits_converted":2,"revenue":2},"idgoal=5":{"nb_conversions":1,"nb_visits_converted":1,"revenue":5},"idgoal=6":{"nb_conversions":2,"nb_visits_converted":2,"revenue":4},"idgoal=7":{"nb_conversions":16,"nb_visits_converted":16,"revenue":16},"idgoal=8":{"nb_conversions":13,"nb_visits_converted":13,"revenue":0},"idgoal=10":{"nb_conversions":1,"nb_visits_converted":1,"revenue":0}},"nb_conversions":45,"revenue":633.7,"region":"xx","country":"xx","country_name":"Unknown","region_name":"Unknown","logo":"plugins\/Morpheus\/icons\/dist\/flags\/xx.png"}];
for (var i = 0; i < dataSet.length; i++) {
// Upon testing your linked data, some of them doesn't have goals key.
// Be sure to only access those who have goals to avoid encountering an error.
if(dataSet[i]['goals']) {
Object.keys(dataSet[i]['goals']).forEach(function (idgoal){
Logger.log(dataSet[i]['goals'][idgoal]['nb_conversions']);
});
}
}
Output:
Note:
I recommend you format the data or view it in a site like this one. It really helps a lot.
The nb_conversions being fetched above are only the ones under the goals key.
If some idgoals doesnt have nb_conversions, just skip them like in goals above. The linked data above all has nb_conversions so I didn't include them for now.
References
Object.keys()
I've been using this function to erase certain rows depending on the name of a cell in a column, for some reason it works, but after it finishes it just gives me an error message.
Exception: Service Spreadsheets failed while accessing document with id #################################################.
function erase() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var range = 'J:J';
var object = 'Delete';
var name = 'Roster';
var sheet = spreadsheet.getSheetByName(name);
var row = sheet.getRange(range);
var value = row.getValues();
for (var i = value.length - 1; i >= 0; i--)
if (value[0, i] == object)
sheet.deleteRow(i + 1);
}
This looks to be a known issue from Google's side which has been reported on Issue Tracker. I suggest you star the issue from here and eventually add a comment saying that you are affected by it.
As a possible workaround, you can try adding SpreadsheetApp.flush() before this line here var row = sheet.getRange(range);.
I'm not familiar with google sheets specifically, but just with general syntax knowledge, I feel like the issue would surround, var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();. Are you sure you arn't supposed to put anything inside the getActiveSreadshee(-here-)??
I am using this script function to check if my cell functions in sheet has any errors or not.
Here is the code but it does not seems to be working. It keeps on saying no error when i have an error in a cell
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourcename = "Sheet1";
var source = ss.getSheetByName(sourcename);
var cell = source.getRange("A1:AG30");
function isError2(cell) {
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
if (errorValues.includes(cell) != true) {
Logger.log("no error");
} else{
Logger.log("some error");
}
}
function isError2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourcename = "Sheet1";
var source = ss.getSheetByName(sourcename);
var cell = source.getRange("A1:AG30");
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
if (errorValues.includes(cell) != true) {
Logger.log("no error");
} else{
Logger.log("some error");
}
}
Updated the approach but still having no luck with the desired output
var mysheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var sheet1 = SpreadsheetApp.setActiveSheet(mysheet);
function findErrors(sheet) {
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
var singleSheetArray = [];
var name = sheet1.getName();
// how many cells in the sheet currently
var maxRows = sheet1.getMaxRows();
var maxCols = sheet1.getMaxColumns();
var totalCells = maxRows * maxCols;
// how many cells have data in them
var r = sheet1.getLastRow();
var c = sheet1.getLastColumn();
var data_counter = r * c;
if (data_counter !== 0) {
var dataRange = sheet1.getRange(1,1,r,c);
var dataValues = dataRange.getValues();
dataValues.forEach(function(row) {
row.forEach(function(cell) {
if ((errorValues.indexOf(cell) === -1) ) {
SpreadsheetApp.getUi().alert("no errors in "+cell);
data_counter --;
}
});
});
}
}
Problem
Unable to check whether the cell has an error
Explanation
The issue you are facing is a simple type mismatch. getRange() method returns an instance of Range, while you try to compare it to a member of a errorValues array, which consists of strings. Therefore, errorValues.includes(cell) will always be false, hence first block of the conditional statement executing.
Solution
Use getValues() on the range, it will return you a 2-dimensional array of values. If you are only interested in one row (which you probably are), extract it and loop over the cells with some (or every) method, doing the same comparison.
Notes
On using global variables in custom functions and in GAS in general. You can use them, GAS environment is a JavaScript runtime with a convenience layer that simplifies working with Google APIs, nearly everything that's valid in JS is valid here. That being said, do treat global variables as if they don't exist - unless you know exactly what you are doing.
References
getRange method reference
getValues method reference
Custom functions guide
every method reference on MDN (see some there)
Try to move the 4 variables inside your function. Apps script does not support global variables. So the function does not recognize the var cell.
EDIT: Detect formula errors in Google Sheets using Script
I set up some code to copy and paste a certain value from the formula using form submissions as a trigger. It worked! But now it's giving me a "too many simultaneous invocations" error with reference to line 3.
It has not been called in excess of 20 times a day (as I know is the set limit) so I'm imagining I did something off with my code... (I'm NOT a JS guy.)
function pasteValue(){
var sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('INVOICES')
var lastRow = sheet.getDataRange().getValues();
lastRow.forEach(function (row,index) {
if (row[1] == "") {
lastRow.length = index;
}
});
var newRange = sheet.getRange(lastRow.length,13);
newRange.copyTo(newRange, {contentsOnly: true})
sheet.setActiveRange(newRange);
}
If what you want is to remove the formulas, its more straightforward to do something like this with "display values":
function pasteValue(){
var sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('INVOICES')
var data = sheet.getDataRange().getDisplayValues();
sheet.getRange(1, 1,data.length, data[0].length).setValues(data);
}