Paste as Value when cell is empty (google-apps-script) - google-apps-script

Currently I am using the following script:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange('Sheet1!C16:C16');
source.copyTo(ss.getRange('Sheet2!A1'), {contentsOnly: true});
source.clear();
}
However I want to append the pasted data in sheet2 with new data that is generated weekly.
So once a week sheet1 is updated and the value in 'Sheet1!C16' will change. I want to append this in 'Sheet2!A2'. and so forth.
So how can I edit this script to make sure the new value is copied in the next empty cell (so when 'Sheet2!A1' has a value get the new value from 'Sheet1!C16' and copy it to 'Sheet2!A2'. And when 'Sheet2!A1'is has a value, copy the new value from 'Sheet1!C16' to 'Sheet2!A3'
I need to to this for all weeks of the year (so just to be safe 53 weeks)
Thnx in advance!

It depends, you can do a few things.
The first one is the easiest, however there is a condition. If each week you copy to cell A1 → A2 → A3 and just keep going down, then each week, that data that you copy over is always the lowest. So for example if you wish to copy data to cell A3 that means that the last row to have any data in any column is row 2. That way all you need to do is get the range like this: ss.getRange(ss.getLastRow() + 1, 1)
The other method is to use PropertiesService to store which row is the last one in use. On script run, get that value
var nextRow = PropertiesService.getScriptProperties().getProperty('property we added before')
and then when you get the target range you use
ss.getRange(nextRow, 1)
PropertiesService.getScriptProperties().setProperty('property we added before', nextRow + 1)
that way you get the next row each time and you update the property for the next time you wish to run. With this you also need to keep in mind that you might want to reset the counter after the year.

Related

Create Unique ID from 0 to Upward Google Sheets

I have a sheet where data is being added to the last empty row and inserting the new row between the rows which has already data.
I want to create a Unique Numeric number that will be 0 to upward in sequence. Like we use =IF(B3<>"",B2+1,"").
But when new row is added the formula is missed I want to Add unique number for each row.
Because when you insert the row all values are bonded but when you type anything in newly added row in Col B all the number goes disturb. It should work like timestamp once a number is allotted to specific row data it should not change even new row is inserted within data.
For example If script has assigned number 1 to 7 and new row inserted then it should assign new row a number 8 even new row is inserted with data in col B
Your help will be appreciated
ALTERNATIVE SUGGESTION
If I have understood your goal correctly, you may try this custom script below that you can copy and paste as a bound script to your Spreadsheet file:
UPDATED Script
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getRange("B2:B").getValues().filter(String); //Add the range where data you want to have IDs, on my end, it's B2 and below (B2:B)
var ids = [];
var lastRow;
for(row=0; row<=data.length-1; row++){
ids.push([row]);
}
lastRow = ids.length + 1;
ss.getRange("A2:A"+lastRow).setValues(ids);
}
SAMPLE DEMONSTRATION
The custom function will add IDs starting on the cell A2 and below once you run it for the first time from the Apps Script editor:
When new added data on cell B10 has been entered:
In the top row,
=ARRAYFORMULA({"ID";SEQUENCE(COUNTA(B:B)+0)})
Change 0 to 1 or 2, if you want some blank row offset.

Writing to a cell based on todays date

I am learning coding in Sheets, and have already jigsawed together a couple of games (based off very limited coding knowledge. Very fun to see it come together
Next task:
I am logging my hours spent doing "Growth" things (like learning, exercise, work etc.) vs "Leisure" things (like TV, games, FB scrolling etc). Up until now I just scroll down to today's date and add in the numbers manually. Would be fun to have a button at the top of my sheet that just adds hours to the "Growth" or "Leisure" cells for today.
I have used formulae in the cell G371 to reveal the A1 notation of my target cell, hoping I can use this info in a script to write to that cell:
=substitute(Cell("address",vlookup(A1,A2:D367,3)),"$","")
Where cell A1 contains =today()
and A2:A367 are all the dates in the year.
and columns C and D hold numbers for growth and leisure respectively.
Then I tried this code to try to see how to write to a cell. I realise I am probably missing some very fundamental knowledge...
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cellname = ss.getRange('G371') // makes cellname refer to G371
var input = cellname.getValue() // makes 'input' return the contents of G371, in today's case its 'C120'
var test = ss.getRange(input) // hopefully reads 'C120' instead of "input"
test.setValue(1) // setting value to 1 for now, as I'm just testing cell
// referencing. later I will work on figuring out the
// math for the buttons. I'm not there yet.
So it didn't work. apparently the problem is with ss.getRange(input) but I don't know what to do about that.
So my question is how to write to a cell that is named in another cell?
hope it makes sense
Thanks!
PS Here is a copy of the sheet
https://docs.google.com/spreadsheets/d/1KkoCb8kY1XICMeB9bx65HXsldCS-fa75xJCaU52WGg8/edit?usp=sharing
The formula in the cell might be messing with the value you retrieve. To make sure that does not happen, you can use getDisplayValue() instead of getValue().
Another way:
Also, if you just want to retrieve the cell where to write today's growth (or leisure), you don't need to follow this roundabout way of creating a formula in another cell to reference this one. You can do this instead (check comments):
function todayGrowthCell() {
var sheet = SpreadsheetApp.getActiveSheet();
var date = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "d/M"); // Format today's date as in spreadsheet, in order to compare
var firstRow = 2; // Row where days start
var column = 3; // Column C (Growth)
var dates = sheet.getRange(2, 1, 366).getDisplayValues().map(row => row[0]); // Retrieve columns with dates (its display value, in order to compare with today's date, which is formatted accordingly)
var row = dates.indexOf(date) + firstRow; // Today's row
var cell = sheet.getRange(row, column); // Today's growth cell
cell.setValue(1); // Set value to today's growth cell
}

Google Sheets script - If a value in cell 1 hits a new high or low, I need to update cell 2 w/ new value

On my Google Spreadsheet, named 'Portfolio', I have 3 rows:
Row 1 contains formulas for current stock price, such as
=GOOGLEFINANCE("VTI"), for about a dozen stocks going down the row. For this example this is in cell A2.
Row 2, cell A3, will contain data for when the price in A2 reaches a lower amount than A3
Row 3, cell A4, will contain data for when the price in A2 reaches a higher amount than A4
The challenge I'm having, and I feel it's simple but for some reason am racking my brain on it, is I need the value in cells A3 & A4 to stick once it's hit. So if the price of VTI hits a new low during trading hours, I want that low to update to cell A3 and to not change unless it hits a new low later that day or next month. Same goes for the high in A4.
Here's what I have so far in the script editor:
function storeValue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Portfolio');
var A2cell = sheet.getRange('A2').getValues();
var A3cell = sheet.getRange('A3').getValues();
var A4cell = sheet.getRange('A4').getValues();
if (A2cell<=A3cell)
{
A3cell.setValue('A2');
}
};
I played around with this a little bit. I thought I'd share it with you and see how quickly you can shoot some holes through it.
The v1 parameter is the Cell reference to the cell you want to watch.
The name parameter is a name given to that value that will be used in the property service to store the last lowest value so that you can use the formula in more than one cell without interacting with other instances.
One of the issues I had was that I don't know if it's possible to determine where the formula has been located or where the cell that your monitoring is located if I could then I could use the cell A1 notation as the name.
function WATCHFORNEWLOWS(v1,name){
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var ps=PropertiesService.getScriptProperties();
if(!ps.getProperty(name))ps.setProperty(name,v1);
if(v1<ps.getProperty(name)) {
ps.setProperty(name,v1);
return v1;
}else{
return parseInt(ps.getProperty(name));
}
}
I hope this helps but I have significant doubts.
Your problem can be solved by using the GOOGLEFINANCE formulas.
If you read the documentation for it, the second parameter is what value you want to fetch.
In your case, you want your cells to be:
=GOOGLEFINANCE('VTI','high')
=GOOGLEFINANCE('VTI','low')
Hope this helps!

Set Google Script to retrieve the value of a certain cell and record that every day/week

I am using a Google Sheet to track my portfolio and I have a cell that calculates the total current market value of my portfolio from various parts of the sheet.
I am trying to see if it is possible to create a script that will record the date as well as the market value (the value only, not the formula) automatically from this cell every day. I know it is possible to set a trigger to run the code weekly/daily, but am having trouble with the code itself.
I can think of 2 approaches. I wasn't sure how to code the second implementation, and what I have so far for the first implementation is below.
1) (First, use Cell A1 as a counter. Set initial value to, say, 3.)
function recordValue() {
//read the counter in Cell A1
var counter = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("A1")
//record current date in cell B&(contents of cell A1)
var dateCell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("B"&counter)
outputRange.setValues(Utilities.formatDate(new Date(), Session.getTimeZone(), 'MM-dd-yyyy'));
//read the current market value in 'Summary'!A1 and record it in cell C&(contents of cell A1)
var marketValue = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Summary").getRange("A1:A1");
var outputCell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("C"&counter);
outputCell.setValues(marketValue);
//add 1 to the counter in cell A1
counter.setValues(counter + 1);
};
2) Record the current date in the cell directly below, then read the current market value in 'SheetA'!A1 and record it in the cell to the right of the date. Then create a new, empty row directly below (ie pushing the recently written data down by one row)
I'm new to Google Sheets and don't have much programming knowledge. Will either of the above approaches work (and work well with a time-driven trigger)? What's wrong with the current code I have for the first implemetation?
Thanks!
I made some changes in your code because you don't use the getValue() .
I don't really understand exactly what you want to do but the code below works :
function recordValue() {
//read the counter in Cell A1
var counter = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("A1");
//record current date in cell B&(contents of cell A1)
var dateCell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("B"+counter.getValue());
dateCell.setValue(new Date());
//read the current market value in 'Summary'!A1 and record it in cell C&(contents of cell A1)
var marketValue = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Summary").getRange("A1");
var outputCell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThisSheet").getRange("C"+counter.getValue());
outputCell.setValue(marketValue.getValue());
//add 1 to the counter in cell A1
counter.setValue(counter.getValue() + 1);
}

Google Apps Script - How to copy a column(s) to another sheet at next available column

I have a requirement where I need to take values from one column (or more) and copy them to another sheet in the next available column (s). I have written a script like this. It does copy the values from one column but it has no way to move forward for taking another snapshot of new data in same source column to destination sheet's next free column.
*//keep a copy of Sales numbers for every month
function readSalesNum() {
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales plan");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SalesRecordsMonthly");
// Copy from 17th row, 4th column, all rows for one column
var rangeToCopy = sheetFrom.getRange(17, 4, sheetFrom.getMaxRows(), 1);
//Paste to another sheet from first cell onwards
rangeToCopy.copyTo(sheetTo.getRange(1, 1));
}*
I am sorry about the poor formatting :( I need to modify this script to mention any set of columns from source sheet and copy them to destination sheet. And for new month, it should do the same in next set of columns, instead of overwriting as it does now. Also, the copy should happen only for values which is missing yet. I know there's an option of ContentOnly in script but not sure how to use it.
If I understood correctly, here is a code that does what you wanted, ie get the values from one sheet in column4 from row 17 and copy it to the other sheet without overwriting to columns starting at row 1
function readSalesNum() {
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales plan");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SalesRecordsMonthly");
// Copy from 17th row, 4th column, all rows for one column
var valuesToCopy = sheetFrom.getRange(17, 4, sheetFrom.getLastRow(), 1).getValues();
//Paste to another sheet from first cell onwards
sheetTo.getRange(1,sheetTo.getLastColumn()+1,valuesToCopy.length,1).setValues(valuesToCopy);
}
test sheet here, make a copy to run the script - view only
This covers only the first part of your question, the second part was a bit confusing (as mentioned in my comment above).
The entire 4th column & 17th row onward can be appended as a column into a different sheet with this approach also.
var sheetfrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetfrom');
var sheetto = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetto');
sheetfrom.getRange(17, 4, sheetfrom.getLastRow(), 1).copyTo(sheetto.getRange(1,
sheetTo.getLastColumn()+1, sheetfrom.getLastRow()-17, 1), {
contentsOnly: true
});
This also overcomes the empty cell problem of copying data from some Formula outputs.
Try this
*//keep a copy of Sales numbers for every month
function readSalesNum() {
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales plan");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SalesRecordsMonthly");
// Copy from 17th row, 4th column, all rows for one column
var rangeValues = sheetFrom.getRange(17, 4, 1, sheetFrom.getMaxRows()).getValues();
//Paste to another sheet from first cell onwards
sheetTo.appendRow(rangeValues[0]);
}
This will do what you want with the range you suggested. However, looks like you're trying to get two different ranges so you'll have to accommodate that.