If the cell contains the word "xxx" then do "xxx" - if-statement

I am working on a spreadsheet and I am trying to create a script, but I don't know how to do this:
I want to write an if statement where if the last row of column B contains the word, let's say "flower", then do something.
Can you please help me?
Thank you in advance.

Here is a working example of how you can use Google Scripts to do an if statement. Paste this into the script editor, then run it. If A1 has the value 1, then it will change B2 to "Yay!", otherwise B2 will be "Really?!"
function myFunction()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("A1"); //gets a cell to test the value of
if (range.getValue == 1)
{
sheet.getRange("B2").setValue("Yay!") //sets the value of B2 if true
}
else
{
sheet.getRange("B2").setValue("Really?!") //sets the value of B2 if false
}
}
You can also add in else if if you want to add additional conditions, then whatever manipulation or function you want to do needs to inside the brackets

Related

Lookup and clear cell content google script

Sorry, I am new to scripting and this is probably a simple one to write; apologies!
I am trying to create a script that gets a range of order numbers in a column, then looks it up on another tab, and then clears a certain cell in that row.
I can get the script to look up the 1st ordernumber at the top of the list andd clear the cell I need clearing, but I cannot work out how to lookup and clear more than one order number at a time.
The logger returns all the values, so I think I need a loop, but I do not knwo where to start with that.
This is for a work project, but I have created a basic sample sheet to play around with:
https://docs.google.com/spreadsheets/d/19koKxFcOfWRz0mEaYs_lHQFgBrU19kDoeYaBY2WBe98/edit?usp=sharing
Can anyone help??
Thanks,
John
Here is the script so far:
function clearpostagecells(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('Order Control');
var sheet2 = ss.getSheetByName('Order Database');
var find = sheet1.getRange(2,2,sheet1.getLastRow()-1).getDisplayValues();
Logger.log(find)
var values = sheet2.getRange(2, 1, sheet2.getLastRow()-1).getDisplayValues();
for (var i = 0; i < values.length; i++) {
var row = "";
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == find) {
row = i+2;
sheet2.getRange(row,7).clearContent();
}
}
}}

format TextField as you type numbers and grouping

I'm having trouble doing something that should be straightforward simple on a good and clean framework, but with SwiftUI is all a big problem.
I simply need a user to be able to type in a TextField, showing only the numPad, and have the numbers automatically grouped as in 3,000,000 as the user types. Also, if the user taps anywhere in the field to correct a mistaken number, the focus should go to the correct tapped place and the user should be able to erase, keep the focus on the same position, and type the new corrected number. Something as simple as that.
Well, there are multiple problems I'm experiencing:
If using a formatter, the formatted number will only display after the field loses focus (i.e. it will show as 3000000 and then after losing focus, 3,000,000). That shouldn't be a great deal of a problem, but if I focus the field again to add more numbers, it ends up typing something like 3,000,000123 and after losing focus it will not recognize anything after the last 0, so it erases 123. Also, the numPad doesn't have a comma to type it manually.
That's the following case:
#State var number: Int = 0
let numberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.generatesDecimalNumbers = true
numberFormatter.maximumFractionDigits = 0
numberFormatter.groupingSize = 3
return numberFormatter
}()
TextField("1000", value: $number, formatter: numberFormatter)
.keyboardType(.numberPad)
If using Combine, the moment a user tries to correct a digit in the middle of the number, the focus goes to the end of the field, screwing the user experience and making people angry.
For this, I'm using this code:
#State var text: String = ""
TextField("1000", text: $text)
.keyboardType: .numberPad)
.onReceive(Just(text)) { _ in formatNumber() }
func formatNumber() {
if (text.count == 0) {
return
}
let filtered = text.filter { "0123456789".contains($0) }
let groups: Int = filtered.count / 3
let remaining: Int = filtered.count % 3
var res: String = ""
if (remaining > 0) {
res += filtered.substring(with: 0 ..< remaining)
res += ","
}
for i in 0 ..< groups {
res += filtered.substring(with: (remaining + i*3) ..< (remaining + (i+1)*3))
res += ","
}
res.removeLast(1)
text = res
}
Is there any clean solution to something as basic as this?
I use normally the .onChange Modifier directly attached to the TextField, like
TextField("Value:", text: $depotActionWertString)
.onChange(of: depotActionWertString) { _ in
let filtered = depotActionWertString.filter {"-0123456789.".contains($0)}
depotActionWertString = filtered
} // .onChange
It is more compact for the checks of the user input and you may combine it with the .onRecive statement for formatting.
For the first case in simple Versions for displaying text I use often the combination Text with String(format:...., like
Text("\(String(format: "%.2f", self._model.wrappedValue.progress * 100)) %")
I think its more a style question as to be right ore wrong....
I don't know if this is the most optimal solution, but one possible solution using Combine without losing the cursor position is to check the length of the published value.
Since the cursor moves to the end of the text because you updated your textfield with the subscriber, you can solve this problem by preventing your subscriber from updating the published value when you edit your text in the middle. Since when you edit, you always start by deleting, you can then just check in your subscriber whether the length of new value is shorter than the length of your old value. If it is, then just return.
I tried the following implementation and it works:
.sink { value in
let filtered = value.filter { "0123456789".contains($0) }
//check is just an Int saving the length of the old value
if filtered.count > 3 && filtered.count >= self.check {
//withCommas is just a formatter
self.text = String(Int(filtered)!.withCommas())
}
self.check = filtered.count
}
Note there are also some problems with this implementation:
since it will not update when you delete, you may end up with something like this: 123,456,789 and the user deleted "456" to become 123,,789. It won't autocorrect itself. I haven't figured out a way to make the commas autocorrect while keeping the cursor in the same place either.
the above implementation force unwrapped optional, which might cause a crash.

Google Sheets - If statement to populate cell

It feels like this should be really easy, but I keep getting errors related to circular logic.
Column C "Total" will always be entered by the user first. If user enters number in Column B "Variable" then Column A "Fixed" will be populated with C - B. If user enters number in Column A "Fixed", then Column B "Variable" will be populated with C - A.
https://docs.google.com/spreadsheets/d/1xBbU6A_MDK6fyLjdFUD7X06b7BQ1VhQ-FWQBET4cLso/edit?usp=sharing
You are trying to add formulas that will always need to rely on eachother to produce an output and as result of that, it will run into a Circualr Dependency error.
Possible solution:
Try using the "Iterative Calculation" option under File –> Spreadsheet Settings –> Calculation. You can see the description for Iterative Calculation here.
Here is one way to avoid circular references: do not hand enter any formulas, but use an onEdit() script to insert formulas programmatically only when necessary.
The following script will enter a formula in column B when column A is edited, and vice versa:
function onEdit(e) {
if (!e) {
throw new Error('Please do not run the script in the script editor window. It runs automatically when you hand edit the spreadsheet.');
}
const watchSheet = /^(Sheet1|Sheet2|Sheet3|Sheet4)$/i;
const watchColumns = [
{
colNumber: 1,
formula: '=C:C - B:B',
},
{
colNumber: 2,
formula: '=C:C - A:A',
},
];
const sheet = e.range.getSheet();
if (!sheet.getName().match(watchSheet)) {
return;
}
const editedColumn = watchColumns.filter(column => column.colNumber === e.range.columnStart)[0];
if (!editedColumn) {
return;
}
const updateColumns = watchColumns.filter(column => column.colNumber !== editedColumn.colNumber);
updateColumns.forEach(column => {
sheet
.getRange(e.range.rowStart, column.colNumber)
.setFormula(column.formula);
});
}

Google Sheets If Function Not running when true

I wanted to add a button to a report in google sheets. The button works but you can not use it on a phone so I'm told you must use onEdit. The problem I'm having is to only make changes when the certain box is edited, but when it is the correct box it seems google freezes and doesn't run the script.
I've already tried with my if as (row = 8) , (Row == 8) and (Row == "8").
function onEdit(evt) {
var range = evt.range;
var row = range.getRow().toString();
Logger.log("line 1");
Logger.log("edited!! Row: " + row + " and column: " + range.getColumn ());
if (row == "8"){ // && range.getColumn() = 6 ){ (This bit is for after I figure the row issue out.
Logger.Log("right");
} else {// esstsgs
Logger.log("Wasnt the right cell");
}
Logger.log("Done the thing");
}
So with that code, if I edit any row but 8 my log looks like:
line 1 edited!!
Row x and Column x
done the thing
But if it is row 8 my log says:
line 1
Edited!! Row x and Column x
And nothing more, when is it freezing in the if statement?
Let me know what you would really like to do with this and I'll set it up for you. For now hopefully this will help you to figure the logic.
I don't use Logger.log() for debugging this kind of code. Instead I use the e.source.toast() function.
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()!='Sheet189')return;//this is important so that you don't get edits from unwanted pages
//e.source.toast('Flag1');
if(e.range.rowStart==8 && e.range.columnStart==6) {
var msg=Utilities.formatString('You are editing %s.',sh.getRange(e.range.rowStart,e.range.columnStart).getA1Notation());
SpreadsheetApp.getUi().alert(msg);
}
if(e.range.rowStart!=8 || e.range.columnStart!=6) {
var msg=Utilities.formatString('You are not editing F8. Instead you are editing %s.',sh.getRange(e.range.rowStart,e.range.columnStart).getA1Notation());
SpreadsheetApp.getUi().alert(msg);
}
}
You will probably want to change the sheet number before running this. I didn't set up the Logger.log because I don't like to use it for this kind of code. I did test this and it works fine.
I'd like to point out some mistakes in your code first of all.
You don't need to make the Row variable a string. var row = range.getRow(); is just fine.
You are always Logging "Line 1", why not update it to actually say which line was updated? Logger.log("line " + row);
Your code will output "Done the thing" regardless of what it did. Maybe just say it did anything when it's the right box?
Your fixed code would look like:
function onEdit(evt) {
var range = evt.range;
var row = range.getRow();
var col = range.getColumn();
Logger.log("line " + row + "edited!! Row: " + row + " and column: " + col);
if (row == 8 && col == 6 ) {
Logger.log("Right cell. Did the thing.");
//Call here whatever you want to trigger when this cell changes.
} //Don't need a "else" if you are not going process anything
}
Hope this helps!

C# Loop through a collection and assign each object to a variable

I am sure this is quite simple but I cannot seem to get this right.
I have a built up a ICollection of Users. This collection could have 1 or many.
I now want to loop through this collection and assign a variable to each user that I can then use to fill in a spread sheet.
At present I have this code :
string username = null;
foreach (var user in dailyReport)
{
username = user.UserName;
}
Cell cell= worksheet.Cells["B5"];
cell.PutValue(username);
Now obviously this just puts the last user of the collection into cell B5!
How do I collect all user.UserNames so I can place them in B5, B6, B7 and so on????
To get a list of the user names:
List<string> userNames = dailyReport.Select( x=> x.UserName).ToList();
Alternatively you can just do the assignment in the loop directly:
int index = 5;
foreach (var user in dailyReport)
{
Cell cell= worksheet.Cells["B"+ index.ToString()];
cell.PutValue(user.UserName);
index++;
}
You need to put the value inside the foreach loop. The specific thing you are asking for--getting a different variable for every value in the collection--is not possible, and isn't what you want anyway.
string column = "B"; // or whatever your column is
int row = 1; // or whatever your starting value is
foreach (var user in dailyReport)
{
string username = user.UserName;
string cellAddress = String.Format("{0}{1}", column, row);
Cell cell = worksheet.Cells[cellAddress];
cell.PutValue(username);
row++; // make sure to increment the row, or every username goes in the same cell
}
int i = 5;
foreach (var user in dailyReport)
{
worksheet.Cells["B" + (i++).ToString()].PutValue(user.UserName);
}