GoogleScript delete my HYPERLINK (Google SpreadSheet) - google-apps-script

Situation:
I have the following script, that run every 1 hours. This script insert "Update Age", I mean how many days past from DATE1 to DATE2.
Script 1: Script Link
Problem:
Column A: This column have an hyperlink. (Tickets# Numbers)
Column F & G: Date 1 and Date 2
Column H: The result of the Script 1
In the coulmn A, I have other script that insert Hyperlink... See Script Link 2.
This Script 2, run OnEdit but the Script 1 run every 1 hour.
When the script 1 run, the formula or Hyperlink is deleted only appear the data in cell.
Question:
Does exist any way that when the script 1 run, not delete the hyperlink or apply the hyperlink to all rows starting for the second 2 rows, the hyperlink.
SCRIPT FOR INSERT LINK:
function InsertLink(e)
{
var actSht = e.source.getActiveSheet();
if (actSht.getName() == ['ISP1']){
var activeCell = actSht.getActiveCell(); //Detec the ActiveCell
//var activeCell = event.range;
var activeCellValue = e.value;
var column = activeCell.getColumn();
var colNums = [1]; //Columns, whose edit is considered
if(colNums.indexOf(column) == -1) return; //If column other than considered then return
var row = activeCell.getRow();
if(row < 2) return; //If header row then return
var length = String(activeCellValue).length;
if (!e.value)
{
activeCell.setValue()
}
else if(length > 2)
{
activeCell.setValue('=HYPERLINK' + '("https://www.example.com/id='+activeCellValue+'";"'+activeCellValue+'")');
}
}
}
SCRIPT UPDATE:
// Create a timer trigger that will call "shellUpdateAge" every 30 minutes
// This function will run only for this particular sheets
function shellUpdateAge(){
var sheets = ['ISP1'];
for (var s in sheets){
toUpdateAge(sheets[s]);
}
}
function toUpdateAge(sheetName){
var ss = SpreadsheetApp.openById('1WmEwSLzqxOj7xkjokmor5B_HpMdabbEAGXiYeQwpIl8');
var sh = ss.getSheetByName(sheetName);
var data = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn()).getValues();
for(var n=0;n<data.length;++n){
if(typeof(data[n][6])=='object'){
data[n][7]=dayToToday(data[n][6])
}
}
sh.getRange(1,1,data.length,data[0].length).setValues(data)
}
function dayToToday(x){
var refcell = x;;// get value in column A to get the reference date
var refTime = new Date(refcell);
var ref = refTime.setHours(0,0,0,0)/(24*3600000);// set hours, minutes, seconds and milliseconds to 0 if necessary and get number of days
var today = new Date();
var TD = today.setHours(0,0,0,0)/(24*3600000);// set hours, minutes, seconds and milliseconds to 0 if necessary and get number of days
var day = parseInt(TD-ref);// get the difference in days (integer value )
return day ; // return result that will be in cell
}
DATA:
A2: =HYPERLINK("https://www.example.com/id=12345";"12345")
Note: The Hyperlink appear for every row in the column A when I ingress the Ticket ID.
F: 12/08/2014 18:08:00 (This Value is the DATA2)
G: 13/08/2014 18:08:00 (This Value is the DATE2)
H: The update age, insert the result from DATE2-DATE1. In this example the script will return 1 day.
Now the problem is when the script Update Age run, the script update the column G and delete the formula in column A.

I would just get and set the bare minimum, so you're not involving the HYPERLINK column:
function toUpdateAge(sheetName){
var ss = SpreadsheetApp.openById('1WmEwSLzqxOj7xkjokmor5B_HpMdabbEAGXiYeQwpIl8');
var sh = ss.getSheetByName(sheetName);
var range = sh.getRange(1,7,sh.getLastRow(),2);
var data = range.getValues();
for(var n=0;n<data.length;++n){
if(typeof(data[n][0])=='object'){
data[n][1]=dayToToday(data[n][0]);
}
}
range.setValues(data);
}
As an aside, you wouldn't consider a spreadsheet array formula for the date difference and HYPERLINK columns?

Related

Google app script for loop is extremely slow

I have a pivot table set up in a google sheet file where I've labeled the sheet pivot table 1. I want to get each value of the first column of the pivot, duplicate each values 12 times in an array and paste these values in the 3rd column of sheet 5. However, it seems extremely slow to do with the script never really completing (just takes 10+ minutes before I've cancelled it).
The pivot has approximately 3000 lines, which would result in a 3000 * 12 = 36000 array.
Any thoughts on how I can optimize this?
function test2() {
// activating current spreadsheet for use
var spreadsheet = SpreadsheetApp.getActive();
//empty array
var array_dept = []
// returns (integer #) the last row of the pivot table 1 sheet that has content
var last_row = spreadsheet.getSheetByName("Pivot Table 1").getLastRow();
// Get value in pivot table 1 from range of row 1 (dept name), column 1, all the way to last row
// Then paste it in sheet5 from row 1, column 3, all the way to the last row defined above
for (var i = 1; i < last_row; i++ )
{
//get value and then paste it in a destination
var value_dept = spreadsheet.getSheetByName("Pivot Table 1").getRange(i,1).getValue();
array_dept.fill(value_dept, -12 + (12*i) , 12*i)
}
destination_dept = spreadsheet.getSheetByName("Sheet5").getRange(1,3, last_row);
destination_dept.setValues(array_dept);
}
You don't need use a loop if you know the first row and the last row on the source column. You can just define the range:
var pivotRange = pivot.getRange(1,1,last_row)
var targetRange = target.getRange(1,3,last_row)
doc ref; this is just one of five methods to define a range.
In the OP script, there would be 3000xgetRange + 3000xgetValue. In this answer there are: 2xgetRange and 1 x getValue. This should account for a substantial amount of script processing. Of course, we know nothing of the rest of the spreadsheet (its size, formula, functions, triggers, etc). But all other things being equal, this should improve the performance of the script.
function test2() {
// activating current spreadsheet for use
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var pivotSheetName = "Pivot Table 1"
var pivot = spreadsheet.getSheetByName(pivotSheetName)
//temporary array
var array_dept = []
// returns (integer #) the last row of the pivot table 1 sheet that has content
var last_row = pivot.getLastRow();
//Logger.log("DEBUG: last row in the pivot table:"+last_row)
var pivotRange = pivot.getRange(1,1,last_row)
// Logger.log("DEBUG: the range for the pivot range = "+pivotRange.getA1Notation())
var pivotData = pivotRange.getValues()
//Then paste it in sheet5 from row 1, column 3, all the way to the last row defined above
var targetSheetName = "Sheet5"
var target = spreadsheet.getSheetByName(targetSheetName)
var targetRange = target.getRange(1,3,last_row)
// Logger.log("DEBUG: the range for the target range = "+targetRange.getA1Notation())
targetRange.setValues(pivotData)
Logger.log("Done")
}

Looping through rows, get values, and add to total on another sheet

So I'm stumped on this in Google Sheets.
Sheet 'Price Calculator' Qty has a of items bought and sold in Column A, separated into 2 named ranges TRADE_QTY and BUY_QTY.
An identical List appears in sheet 'Master Tally', with qtys from previous trades, also in column A.
Have been flipping through multiple windows of examples of code and none seem to be able to provide anything that works.
function TEST() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
//Gets number of rows of each range
var Rows1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getNumRows()
var Rows2 = ss.getRange('\'PRICE CALCULATOR\'!BUY_QTY').getNumRows()
//Gets Starting rows of each range
var Row1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getRow()
var Row2 = ss.getRange('\'PRICE CALCULATOR\'!BUY_QTY').getRow()
for (r=Row1; r<Rows1; r++) {
ss.setActiveSheet(ss.getSheetByName('PRICE CALCULATOR'), true);
var ADD = ss.getRange(r,1).getValue()
if (cell.isBlank()) {
next r
}
else {
ss.setActiveSheet(ss.getSheetByName('Master Tally'), true);
var EXIST = ss.getRange(r,1).getValue()
var TOT = ADD+EXIST
ss.getRange(r,1).setValue(TOT)
}
}
}
Basically i'm try to develop a macro/script that adds the new trade qtys in sheet 'Price Calculator' to the existing qtys in 'Master Tally'
I"m stumped as it keeps throwing me 'Cannot find method getRange(number,number)' and now i'm out of my depth!
Link to the document;
https://docs.google.com/spreadsheets/d/1gIjCqv5KT41wYuJS1Hs1X8yPPUTPY_kGoTuilzxLkSo/edit?usp=sharing
This code suffers from a basic flaw: confusion between Row and Column numbers of an array (which start at 0-zero) with those derived from script commands such as getValue (which start at 1-one).
For example:
for (r=Row1; r<Rows1; r++) {
In this case, the value of Row1 was determined by getRow, so it returns the actual row number. But the loop values will generate the row and column number for an array starting at zero; so this line should read for (r=0; r<Rows1; r++) {
var EXIST = ss.getRange(r,1).getValue()
The purpose of this line is return the "existing qtys in 'Master Tally'", and the range will look in Column A for the value. However the values are actually in column B. So this line will never return an accurate value for "existing qtys".
There are some other things to note:
The existing code makes two getValue calls in every loop; these are time-expensive. The answer improves performance by getting the respective range values just once before the loop.
The update of the quantity sold (setValue(TOT)) is inside the loop. Again this is a time-expensive command. The answer updates the array values within the loop, and then updates the sheet once-only after the loop.
BUY Qty values are irrelevant
function so56017521() {
var ss = SpreadsheetApp.getActive();
//Gets number of rows of each range
var Rows1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getNumRows()
//Logger.log("DEBUG: Number of Rows: Trade Qty="+Rows1);
//Gets Starting rows of each range
var Row1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getRow()
//Logger.log("DEBUG: Start Row: Trade Qty="+Row1);
// setup sheets
var calcsheet = "PRICE CALCULATOR";
var mastersheet = "Master Tally";
var calc = ss.getSheetByName(calcsheet);
var master = ss.getSheetByName(mastersheet);
var masterrows = master.getLastRow();
//Logger.log("DEBUG: Master Last Row = "+masterrows);
// get data for each sheet
var calcrange = calc.getRange(Row1, 1, Rows1);
var calcdata = calcrange.getValues();
var masterrange = master.getRange(3, 2, masterrows - 2);
var masterdata = masterrange.getValues();
//Logger.log("DEBUG: Calc data range = "+calcrange.getA1Notation()+", Master Data Range"+masterrange.getA1Notation());
for (r = 0; r < Rows1; r++) {
Logger.log("r=" + r);
var ADD = calcdata[r][0]; //Trade qty
//Logger.log("DEBUG: r="+r+", ADD value = "+ADD+", ADD.length = "+ADD.toString().length);
if (ADD.toString().length != 0) { // if Trade qty has value
// keep going
//Logger.log("DEBUG: keep going");
var EXIST = masterdata[r][0]; // existing quantity qty sold
Logger.log("DEBUG: r=" + r + ", EXIST = " + EXIST);
var TOT = ADD + EXIST; // sum of trade-in qty plus existing qty
Logger.log("DEBUG: ADD+EXIST = " + TOT);
// update masterdata array
masterdata[r][0] = TOT;
} else {
// nothing to see here
//Logger.log("DEBUG: next r please");
}
}
//update the spreadsheet with the adjusted array values
masterrange.setValues(masterdata);
}

Delete Row If Two Corresponding Cells Match

In my google sheet file, sheet2 is being used as a blacklist wherein colA = a name, colB = date they were blacklisted, colC = date they will be removed from the blacklist (3 months after value in colB). Sheet1 records the responses of a signup form.
I would like a script that will automatically remove the names after their colC date. Perhaps a script that can delete an entire row if two cells match. An example would be if B2 and C2 are equal then delete row 2. This would have to apply to every row.
Any help would be greatly appreciated. Thank you very much.
It wasn't immediately clear which sheet you wanted to remove the name from. My answer assumes that you are removing the name from the blacklist sheet, sheet2.
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var sheet2 = ss.getSheetByName ("sheet2");
var values = sheet2.getDataRange ().getValues ();
var day = 24*3600*1000;
var today = parseInt ((new Date ().setHours (0,0,0,0))/day);
var ssdate; // Date to check, spreadsheet date
// Start at the bottom and move up the file, since all rows will shit up when deleted
for (var i = values.length; i >= 0; i--)
{
try
{
ssdate = values[i][2].getTime () / day; // 2 is for the C column (0 is for the A column)
}
catch (e) {ssdate = null;}
// Testing that the date is today or later to remove from file
if (ssdate && Math.floor (ssdate) >= today)
{
sheet2.deleteRow (i + 1); // Removes name from blacklist.
// i + 1, because it is the row number, which starts at 1
// where arrays start index at 0.
}
}

Google Spreadsheets Script - Copy cell value to another column

I have a spreadsheet which calculates my total bank savings across different accounts.
I would like to write a script which, when run, copies the total savings calculated that day to another column along with a timestamp. The idea is that I can then plot this data in a graph to see the trend in my savings plotted over time.
In practice, that means copying the value of A5 to the first empty row of column B and printing the date in the first empty row of column C.
Does anybody know how this can be done?
Thanks!
Copy this into your spreadsheet script, and set it up as a daily trigger function.
function recordTodaysBalance() {
var sheet = SpreadsheetApp.getActiveSheet();
var balance = sheet.getRange("A5").getValue();
var nextRow = getFirstEmptyRow('B');
// Record current balance and timestamp at end of columns B & C
sheet.getRange(nextRow, 2, 1, 2).setValues([balance,new Date()]);
};
// From https://stackoverflow.com/a/9102463/1677912
function getFirstEmptyRow(columnLetter) {
columnLetter = columnLetter || 'A';
var rangeA1 = columnLetter + ':' + columnLetter;
var spr = SpreadsheetApp.getActiveSpreadsheet();
var column = spr.getRange(rangeA1);
var values = column.getValues(); // get all data in one call
var ct = 0;
while ( values[ct][0] != "" ) {
ct++;
}
return (ct+1); // +1 for compatibility with spreadsheet functions
}
Adapted from this answer.

Automatically move data from one sheet to another in google docs

i have a spreadsheet that i keep track of tasks i need to do, once complete i enter a date in the last column. What i want is for that completed task to be moved to sheet 2.
At present i have sheet 1 named SUD_schedule and i want the completed row of data to be moved to sheet 2 named SUD_archive. I've looked through the forum posts already and i've tried a variation of scripts but so far no luck. The closest i have come is this script:
function onEdit() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();//Original sheet
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];//target sheet
// to act on only one sheet, check the sheet name here:
//If it si not first sheet, it will do nothing
if (sheet1.getSheetName() != "SUD_schedule") {
return;
}
//Get Row and column index of active cell.
var rowIndex = sheet1.getActiveRange().getRowIndex();
var colIndex = sheet1.getActiveRange().getColumnIndex();
//If the selected column is 10th and it is not a header row
if (colIndex == 16 && rowIndex > 1) {
//Get the data from the current row
var data = sheet1.getRange(rowIndex,1,1,9).getValues();
var lastRow2;
(sheet2.getLastRow()==0)?lastRow2=1:lastRow2=sheet2.getLastRow()+1;
//Copy the data to the lastRow+1th row in target sheet
sheet2.getRange(lastRow2,1,1,data[0].length).setValues(data);
}
}
Column P (16) is the task complete date, row 1 is frozen and contains column headers.
Can anybody help show where i'm going wrong.
Kind regards
Den
Your code is not generic and you are more complicating your objective. Below will work out your need.
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('SUD_schedule');
var sheet2 = ss.getSheetByName('SUD_archive');
var dateColumn = "16";
var array = []
var range = sheet1.getRange(1, 1, sheet1.getLastRow(), dateColumn);
for (var i = 2; i <= sheet1.getLastRow(); i++) //i iterates from 2 as you say R1 is header
{
if(isValidDate(range.getCell(i, dateColumn).getValue()) == true) //checking if any values on column16 is valid date
{
data = sheet1.getRange(i, 1, 1, dateColumn).getValues(); //Getting the range values of particular row where C16 is date
for (var j = 0; j < dateColumn; j++) //Adding the row in array
{
array.push(data[0][j]);
}
}
if(array.length > 0)
{
sheet2.appendRow(array); //Appending the row in sheet2
array = [];
sheet1.deleteRow(i); //deleting the row in sheet as you said you want to move, if you copy remove this and next line
i=i-1; //managing i value after deleting a row.
}
}
}
//Below function return true if the given String is date, else false
function isValidDate(d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
I am not sure that the syntax you have as used below is entirely correct.
(sheet2.getLastRow()==0)?lastRow2=1:lastRow2=sheet2.getLastRow()+1;
sheet2.getRange(lastRow2,1,1,data[0].length).setValues(data);
What I know will work for certain is if you omit the variable lastRow2 all together and use this instead.
sheet2.getRange(getLastRow+1,1,1,data[0].length).setValues(data);
To complement Joachin's answer, here is how you can adapt that code if you don't have the date in the last row. In the below shown part of the code replace Lastcolumnumber with your last column.
//Getting the range values of particular row where C16 is date
data = sheet1.getRange(i, 1, 1, LASTCOLUMNNUMBER).getValues();
//Adding the row in array
for (var j = 0; j < LASTCOLUMNNUMBER; j++)