I want to create a Script for a Spreadsheet that copies and pastes some values in a loop until a cell returns "Yes".
This is the code I have, but it is not working
function CopyPaste() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var check = spreadsheet.getRange("Hypothesis!C4");
var source = spreadsheet.getRange("Macro!E6:AQ8");
var destination = spreadsheet.getRange("Macro!E12:AQ14");
while(check!= "Yes"){
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_VALUES);
}
}
This is the code that is working on VBA but I canĀ“t implement on Google Scripts.
Sub CopyPaste()
Application.ScreenUpdating = False
Do While Worksheets("Hypothesis").Range("C7") <> "Yes"
Worksheets("Macro").Range("E6:AR8").Copy
Worksheets("Macro").Range("E12:AR14").PasteSpecial xlPasteValues
Loop
Application.ScreenUpdating = True
End Sub
The check variable you are using is returning a Range object and not a value. In order to retrieve the value corresponding to the Hypothesis!C4 you will have to use the getValue() method:
var check = spreadsheet.getRange("Hypothesis!C4").getValue();
Moreover, in the current stage, your while loop is an infinite one since the condition will always return true (if check is different than "Yes"). Taking this into account, you should adjust your while condition such that it performs a correct looping by adding an if condition inside the loop or adjusting the current one such that the check variable will return "Yes".
Reference
Apps Script Range Class - getValue().
Related
I'm working on a macro which will run through the files in the folder and then copy sheets from all excel files to the workbook from which the macro was run.
This part works as charm, what I want to do is to select and copy sheets that match exact name.
For Each wksCurSheet In wbkSrcBook.Sheets
'I reckon I should add some if statement in here
countSheets = countSheets + 1
wksCurSheet.Copy after:=wbkCurBook.Sheets(wbkCurBook.Sheets.Count)
Next
Honestly, I have no idea how to write that statement, examples I found were quite confusing and when I try something by myself, I get weird errors.
If (wksCurSheet.Name == "AO-SC") Then
If (wksCurSheet.Name as String == "AO-SC") Then
If (wksCurSheet.("AO-SC")) Then
What's the correct way?
This is the way to get the specific worksheet through loop:
For Each wksCurSheet In wbkSrcBook.Worksheets
If wksCurSheet.Name = "AO-SC" Then
'Do something
End If
Next
This is how to use it with two worksheets:
If wksCurSheet.Name = "AO-SC" Or wksCurSheet.Name = "SomethingElse" Then
And if the worksheets, you are interestd in are saved in an array, you can use a custom function valueInArray, checking whether the worksheet's name is part of the predefined array:
Public Function valueInArray(myValue As Variant, myArray As Variant) As Boolean
Dim cnt As Long
For cnt = LBound(myArray) To UBound(myArray)
If CStr(myValue) = CStr(myArray(cnt)) Then
valueInArray = True
Exit Function
End If
Next cnt
End Function
This is how to use it:
predefinedArrayWithNames = Array("Sheet1", "Sheet2","Sheet3")
If valueInArray(wksCurSheet.Name, predefinedArrayWithNames) Then
Hi there I have a vba code on my regular excel sheet that works well. I want something that makes the job done on google sheets.
Let me explain what this code does:
So basically, whenever you use a drop down on your sheet, this macro instantly changes the selection you made into a formula that has the same result.
If you ever go and change the value of the choice in the original list, all the cells that currently resolve to that same value "position" will update automatically since they're all formulas.
So can anyone help me to make the same in Google Sheets?
This is a simple gif that show how the vba code works
http://g.recordit.co/DfFslr0iJF.gif
This is the sample file if you guys want to take a look at
https://drive.google.com/file/d/0B8OCuWHp5L8TWDFyR0xDV1d0bTA/view?usp=sharing
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim strValidationList As String
Dim strVal As String
Dim lngNum As Long
On Error GoTo Nevermind
strValidationList = Mid(Target.Validation.Formula1, 2)
strVal = Target.Value
lngNum = Application.WorksheetFunction.Match(strVal, Range(strValidationList), 0)
If strVal <> "" And lngNum > 0 Then
Application.EnableEvents = False
Target.Formula = "=INDEX(" & strValidationList & ", " & lngNum & ")"
End If
Nevermind:
Application.EnableEvents = True
End Sub
You could use the onEdit() trigger. The code below gets the context of the edit by examining the event object passed to the function and dynamically rebuilds validation rule for the target range (in this case, 'A1'). As in your example, the list values reside in column 2:
function onEdit(e){
var sheet = e.source.getActiveSheet();
var range = e.range;
var listValuesCol = 2;
if(range.getColumn() == listValuesCol && sheet.getName() =='yourSheetName'){ // checking if the values were updated
var sourceRange = sheet.getRange(1, listValuesCol, sheet.getLastRow(), 1); //range containing validation rule list values
var targetRange = sheet.getRange(1,1); //target cell, e.g. A1
var newValidationRule = SpreadsheetApp.newDataValidation()
.requireValueInRange(sourceRange, true) //boolean flag for showing or disabling dropdown list
.build();
targetRange.setDataValidation(newValidationRule);
SpreadsheetApp.flush();
}
}
I defined a VBA function that returns a filesize. Now I want to invoke it with a button that's calling a different macro. My expectation is that after running the macro it'll invoke my function at the very end. My problem is that when I put a formula into a cell it will return a current filesize only the moment I enter the formula. When I edit the file, save it and reopen, the =wbksize() will still display the filesize from before my edits.
So the purpose of this macro run by a button is to refresh the filesize value. Here's my attempt to do it.
function:
Function wbksize()
myWbk = Application.ThisWorkbook.FullName
wbksize = FileLen(myWbk)
End Function
refresh:
Worksheets("Sheet2").Range("K1").Calculate
The above doesn't seem to work :/
Function works fine, but refreshing should call function.
Function wbksize() As String
myWbk = Application.ThisWorkbook.FullName
wbksize = Str(FileLen(myWbk))
End Function
Sub Refresh()
Worksheets("Sheet2").Range("K1") = wbksize
End Sub
This may or may not help you in your situation....LINK
I have never needed to use this on excel but it maybe what your looking for, you can set custom functions as 'VOLATILE' which forces excel to run them whenever ANYTHING get calculated, again i have never needed to use this so i cannot comment on any drawbacks or anything but it looks like it may work in your case.
I've tested these, and they both work fine. It depends on what you want your trigger to be: Changing the worksheet, or performing a Calculate on the worksheet.
Put either of these in your Worksheet. The first will trigger on Calculate, the second on Change.
Private Sub Worksheet_Calculate()
Dim lFileLength As Long
Application.EnableEvents = False 'to prevent endless loop
lFileLength = FileLen("\\MyFile\Path\AndName.XLS.XLS")
ThisWorkbook.Sheets("Sheet1").Range("A1").Value = CStr(lFileLength)
MsgBox "You changed THE CELL!"
Application.EnableEvents = True
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lFileLength As Long
Application.EnableEvents = False 'to prevent endless loop
lFileLength = FileLen("\\MyFile\Path\AndName.XLS")
ThisWorkbook.Sheets("Sheet1").Range("B1").Value = CStr(lFileLength)
MsgBox "You changed THE CELL!"
Application.EnableEvents = True
End Sub
When I enter the following function as a UDF in a cell:
Function VisibleBlankCells(r As Range) As Long
On Error Resume Next
VisibleBlankCells = Intersect(r.SpecialCells(xlCellTypeVisible), r.SpecialCells(xlCellTypeBlanks)).Count
On Error GoTo 0
End Function
r.SpecialCells(xlCellTypeBlanks) evaluates ALL cells in r as empty regardless of whether they contain text or not. What might be the cause of this and an alternative solution?
Get rid of the On Error Resume Next for a start - you should always assume that your code will fail and account for it accordingly, simply ignoring errors will just complicate matters.
Secondly ,there is no need to use Intersect - just identify the visible cells directly, and then use a further SpecialCells() method to identify the blank child cells.
Function VisibleBlankCells(r As Range) As Long
VisibleBlankCells = r.SpecialCells(xlCellTypeVisible).SpecialCells(xlCellTypeBlanks).Count
End Function
tested with this:
Sub test_code()
Dim r As Range: Set r = Selection
Debug.Print CountBlanks(r)
End Sub
Function CountBlanks(r As Range) As Long
CountBlanks = r.SpecialCells(xlCellTypeVisible).SpecialCells(xlCellTypeBlanks).Count
End Function
This kind of filter mechanism won't work in an UDF (see this for information on that). I suggest a looping inside your UDF:
Public Function VisibleBlankCells(rng As Range) As Long
Dim i As Integer
Dim cell As Range
i = 0
For Each cell In rng
If cell.Rows.Hidden = False And _
cell.Columns.Hidden = False And _
cell.Value = "" Then
i = i + 1
End If
Next
VisibleBlankCells = i
End Function
However, there may be some problems regarding the updating and functionality:
The value of the UDF only updates after editing the referenced range or calling other UDFs. So if you hide a column or row in that range, it won't have an instant effect
In the (working) execution of your code in a Sub, the visible cells (also) refer to yet unused cells in your worksheet to be "not visible". In my solution however, all cells that are not contained in a hidden row/column are considered visible.
I'm calling VBA function from an Excel worksheet. When I change a cell inside the code of the VBA function, Excel tries to re-execute that function again (and again in the second iteration and ...)
Example: if you have the code:
Function test() As Variant
Range("A1") = 1
test = "test"
End Function
When you use "=test()" anywhere, it will return #VALUE!. A debug will show that when you update A1, it will try to re-execute test().
Can you prevent Excel from doing this? E.g. saying 'don't update any of my numbers until I'm done with this function'? I've tried the Application.Calculation flag, or doing some external concurrency checks, but that doesn't seem to work ...
Try:
Function test() as Variant
test="test"
End Function
As Gary's student says in his comment: UDF's should only change worksheet entries of the cells that call the function, and this value should be returned as a result of the function, not by changing a cell value of an explicit address.
In other words, this does not work:
Function test() As Variant
Range("A1") = 1
test = "test"
End Function
Instead call test() from cell A1 and do this:
Function test() As Variant
test = 1
End Function
If the desired behaviour is to edit multiple cells (the return value of the function AND another cell), this should be implemented through a sub rather than a function.
To answer your specific question of how to stop the Function re-executing when you change A1 or your function, and stop it returning #Value: 1. Use the Excel user interface (Formulas--> calculation options) to change calculation mode to manual 2. add some error trapping to your function like this.
Function test() As Variant
On Error Resume Next
Range("A1") = 1
test = "test"
End Function
as has already been said the function will not change the value of A1