I'm trying to create a pdf of the various sheet in the workbook based on certain criteria in VBA
my current code is
Sub ExportAsPDF()
Dim FolderPath As String
FolderPath = "C:\Users\USER1\Desktop\PDF\pdftest"
'sheet names in ""
Sheets(Array("SHEET1","SHEET2","SHEET3")).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, filename:=FolderPath, _
openafterpublish:=False, ignoreprintareas:=False
MsgBox "All PDFs have been successfully exported."
End Sub
the above works but there are more than 9 sheets and sometimes sheet 2 will be needed sometimes it won't. how do I write the array selection to a variable based on criteria?
if a=1 then add sheet 2 to the array kind thing
Thank You for your help!
You can set up an array with the sheet names, then add Sheet2 if required:
Dim arr, test
test = True 'variable which controls adding sheet2....
arr = Array("Sheet1", "Sheet5") 'array without sheet2
'need to add sheet2?
If test Then
ReDim Preserve arr(LBound(arr) To UBound(arr) + 1)
arr(UBound(arr)) = "Sheet2"
End If
ThisWorkbook.Sheets(arr).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
"C:\Tester\tempo.pdf", Quality:=xlQualityStandard, IncludeDocProperties:=True, _
IgnorePrintAreas:=False, OpenAfterPublish:=True
Function AvoidWB2() As String()
Dim v() As String, i As Long, wbCount As Long
wbCount = ActiveWorkbook.Sheets.Count
ReDim v(1 To wbCount)
For i = 1 To wbCount
If i = 2 Then
'do something here regarding adding sheet 2.
Else
v(i) = ActiveWorkbook.Sheets(i).Name
End If
Next i
AvoidWB2 = v
End Function
Sub ExportAsPDF()
Dim FolderPath As String, vSheetSelection() as Variant
FolderPath = "C:\Users\USER1\Desktop\PDF\pdftest"
'sheet names in ""
'----| Implement Here|
Sheets(AvoidWB2).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, filename:=FolderPath, _
openafterpublish:=False, ignoreprintareas:=False
MsgBox "All PDFs have been successfully exported."
End Sub
Here is an example based on the described requirements.
This example assumes:
You only want to consider excluding Sheet2 from the pdf.
You deterime if Sheet2 is to be included or not by the value in Cell B1 on Sheet2
I've adapted some If...Then conditioning with a For Each...Next loop to your existing code.
Sub ExportAsPDF()
Dim FolderPath As String
Dim SheetsArray As Variant
Dim TargetSheet As Worksheet
Dim ArrayCounter As Long: ArrayCounter = 0
FolderPath = "C:\Users\USER1\Desktop\PDF\pdftest"
'sheet names in ""
If Sheets("Sheet2").Range("B1").Value = "Yes" Then
ReDim SheetsArray(ThisWorkbook.Worksheets.Count - 1)
For Each TargetSheet In ThisWorkbook.Worksheets
SheetsArray(ArrayCounter) = TargetSheet.Name
ArrayCounter = ArrayCounter + 1
Next TargetSheet
Else
ReDim SheetsArray(ThisWorkbook.Worksheets.Count - 2)
For Each TargetSheet In ThisWorkbook.Worksheets
If Not TargetSheet.Name = "Sheet2" Then
SheetsArray(ArrayCounter) = TargetSheet.Name
ArrayCounter = ArrayCounter + 1
End If
Next TargetSheet
End If
ThisWorkbook.Sheets(SheetsArray).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=FolderPath, _
openafterpublish:=False, ignoreprintareas:=False
MsgBox "All PDFs have been successfully exported."
End Sub
If the value of Sheet2.Range("B1") is "Yes" then Sheet2 is included in the pdf, otherwise if it's any other value it is not included.
Explanation:
Relevant documentation:
Using Arrays (Covers setting lower/upper bound of array etc.)
If...Then...Else statement (VBA)
For...Next statement (VBA)
First I evaluate whether Sheet2.Range("B1") = "Yes" to dictate how we will populate the SheetsArray.
The statements are very similar depending on if it's "Yes" or not.
The ReDim SheetsArray is to set the dimension of our Array. Because arrays in VBA are Base 0 by default (meaning the first element of the array is 0, the second element is 1 etc...) I size the array as follows:
If the value is "Yes" the array is sized as 1 less than the number of worksheets. This is to account for the array starting at 0 rather than 1.
If the value is not "Yes" then the array is sized at 2 less than the number of worksheets. This accounts for the array starting at 0 rather than 1 AND that we are not including Sheet2.
The For Each...Next loop then iterates over the Worksheets collection, adding each worksheet name to the array. We have an extra If...Then statement within the code block for if the value is not "Yes" to determine if the TargetSheet is not Sheet2 and add the worksheet name if this condition is met. This will exclude Sheet2 from being added to our array.
The ArrayCounter variable simply increments with each worksheet name added to the array as "To set the value of an individual element, you specify the element's index."
Related
In Sheet1 on the excel sheet I have in Range("B6") I have a code so it might be one code this month but it can also be 3 more code added below in the next and it just could be two new in the next month so the values will keep on changing and number can range between 1 to anything it will be dynamic. Based on these values on the next Sheet2 the date needs to be filtered. So in Sheet2 I have three columns one is Sl_No. one ME_Code (This is what needs to be filtered based on Sheet 1 data) and prices
So I am new in VBA and tried the below code which is not working when there is multiple codes which I am trying to add to an Autofilter Array in VBA.
Here is my code which is not working when I am trying in the else option can someone please help me, I tried few option from StackOverflow itself but did not work
Here is my code,
Sub ToCheckArray()
Dim N As Long
Worksheets("Sheet1").Select
If IsEmpty(Range("B6").Offset(1, 0).Value) Then
Worksheets("Sheet1").Select
arr1 = Array(Range("B6"))
Worksheets("Sheet2").Select
Range("A1:C1").AutoFilter field:=2, Criteria1:=arr1, Operator:=xlFilterValues
Else
Worksheets("Sheet1").Select
'With Sheets("Sheet1")
'N = .Cells(Rows.Count, "B").End(xlDown).Row
'ReDim ary(6 To N)
'For i = 6 To N
'ary(i) = .Cells(i, 1)
'Next i
'End With
arr1 = Array(Range("B6", Range("B6").End(xlDown)))
Worksheets("Sheet2").Select
Range("A1:C1").AutoFilter field:=2, Criteria1:=ary, operator:=xlFilterValues
End If
End Sub
Use
Else
Dim ary As Variant
With Worksheets("Sheet1")
ary = Application.Transpose(.Range("B6", .Cells(Rows.Count, "B").End(xlDown)).Value)
End With
Worksheets("Sheet2").Range("A1:C1").AutoFilter field:=2, Criteria1:=ary, operator:=xlFilterValues
End If
As you see, I avoided Select statement in lieu of a fully qualified range reference up to the sheet reference
So your entire code could be rewritten as follows:
Sub ToCheckArray()
Dim ary As Variant
With Worksheets("Sheet1")
If IsEmpty(.Range("B6").Offset(1, 0).Value) Then
ary = Array(.Range("B6").Value)
Else
ary = Application.Transpose(.Range("B6", .Cells(Rows.Count, "B").End(xlDown)).Value
End If
End With
Worksheets("Sheet2").Range("A1:C1").AutoFilter field:=2, Criteria1:=ary, Operator:=xlFilterValues
End Sub
And should you be sure that Sheet1 has always a value in B6, and possible other values follow it down to the last not empty cell in column B, then it can collapse to:
Sub ToCheckArray()
Dim ary As Variant
With Worksheets("Sheet1")
ary = Application.Transpose(.Range("B6", .Cells(Rows.Count, "B").End(xlUp)).Value
End With
Worksheets("Sheet2").Range("A1:C1").AutoFilter field:=2, Criteria1:=ary, Operator:=xlFilterValues
End Sub
I need to get the Account Numbers into an array which is indicated as 1 on the column select. Results expected is - {FD_002_17,FD_004_17}. I am planning to use this in a Name Range.
Table of interest to subset
I tried using
=INDEX(B2:B6,MATCH(1,A2:A6),1)
But this fails as Match does not return an array.
Using the post (https://stackoverflow.com/a/6755513/4050510) in the SO question that Hugs referred to i came up with the following formula for your need.
Its a array formula that you enter into your first cell, and then fill it downwards using the little handle in the corner of the selected cell.
=IFERROR(INDEX($B$2:$B$6;SMALL(IF($A$2:$A$6=1;ROW($B$2:$B$6)-MIN(ROW($B$2:$B$6))+1;"");ROW(A1)));"")
It is possible to do this. You can assign the named range to a formula such as :
=INDEX(Sheet1!$B:$B, N(IF({1}, MODE.MULT(IF(Sheet1!$A$2:$A$6=1, ROW(Sheet1!$A$2:$A$6)*{1,1})))))
Then you can reference your Named Range like: =INDEX(MyNamedRange, 2)
EDIT:
You can either set a hidden sheet to have a filtered list of the values in a range of cells, or else use VBA:
VBA:
Put this in the worksheet codemodule of the relevant work sheet:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("A:A")) Is Nothing Then Exit Sub
Dim ARange As Range, BRange As Range
Dim i As Long, lastRow As Long, strCount As Long
lastRow = Me.Range("A" & Me.Rows.Count).End(xlUp).Row
Set ARange = Me.Range("A1:A" & lastRow)
Set BRange = Me.Range("B1:B" & lastRow)
Dim stringArr() As String
For i = 1 To lastRow
If ARange.Cells(i, 1).Value = 1 Then
ReDim Preserve stringArr(0 To strCount)
stringArr(strCount) = BRange.Cells(i, 1).Value
strCount = strCount + 1
End If
Next i
Dim str As String
str = Join(stringArr, ",")
Dim dv As Validation
Set dv = Me.Range("DVCell").Validation
If Not dv Is Nothing Then
dv.Modify _
Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, _
Formula1:=str
Else
dv.Add _
Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, _
Formula1:=str
End If
End Sub
To use formulas and a hidden sheet, use the techniques to fill a range of cells, and then assign that dynamic range to the data validation....
My intention was to have the following code compile data from my "Low CPM 1" worksheet into an array and then filter my active worksheet based on this array. While the macro does seem to affect the filters, none of the values get filtered out. Any help on this matter would be greatly appreciated
Sub Macro1()
Dim CPM1Array(0 To 300) As Variant
For i = 2 To UBound(CPM1Array)
CPM1Array(i) = Sheets("Low CPM 1").Cells(i, 2).Value
Next i
ActiveSheet.Range("$A$1:$H$251").AutoFilter Field:=3, Criteria1:=("<>1 to Ubound(CPM1Array)"), Operator:=xlFilterValues
End Sub
There is no simple way with autofilter to achieve what you want. You cannot use Criteria1:="<>MyArray"
Alternative
We know which values we do not want. We can find out what are the values of the relevant column
Simply store the values of the relevant column in an array and then remove the unnecessary values from it by comparing it with the array which has values we do not want.
Remove blank cells from the array
Pass the final array to the autofilter.
In Action
Let's say our worksheet looks like as shown in the below image. I am taking an example of only 15 rows.
Code
Sub Sample()
Dim ws As Worksheet
Dim MyAr(1 To 5) As String
Dim tmpAr As Variant, ArFinal() As String
Dim LRow As Long
ReDim ArFinal(0 To 0)
Set ws = ActiveSheet
'~~> Creating an array of values which we do not want
For i = 1 To 5
MyAr(i) = i
Next i
With ws
'~~> Last Row of Col C sice you will filter on 3rd column
LRow = .Range("C" & .Rows.Count).End(xlUp).Row
'~~> Storing the values form C in the array
tmpAr = .Range("C2:C" & LRow).Value
'~~> Compare and remove values which we do not want
For i = 1 To LRow - 1
For j = 1 To UBound(MyAr)
If tmpAr(i, 1) = MyAr(j) Then tmpAr(i, 1) = ""
Next j
Next i
'~~> Remove blank cells from the array by copying them to a new array
For i = LBound(tmpAr) To UBound(tmpAr)
If tmpAr(i, 1) <> "" Then
ArFinal(UBound(ArFinal)) = tmpAr(i, 1)
ReDim Preserve ArFinal(0 To UBound(ArFinal) + 1)
End If
Next i
'~~> Filter on values which you want. Change range as applicable
.Range("$A$1:$H$15").AutoFilter Field:=3, Criteria1:=ArFinal, Operator:=xlFilterValues
End With
End Sub
Output
I want to select a array of sheets using the Sheets(Array()) method.
The sheets I want to select are named in the cells of my workheet Printlist.
The sheetnames are listed form column D to K.
Not all cells are filled so if I use the folowing function it errors on the rows with blank cells. How can I avoid this error:
This is what the sheet looks like:
And this is the code
Sub PDF_maken()
Dim ws As Worksheet
Dim LR As Long
Dim r As Range
Dim Mypath As String
Dim strarray As String
Set ws = ActiveWorkbook.Worksheets("Printlijst")
LR = ws.Cells(Rows.Count, 1).End(xlUp).Row
For Each r In ws.Range("B20:B20").Cells
If Not IsEmpty("B" & r.Row) Then
Mypath = ws.Range("B" & r.Row).Text
colCheck = 4
Do Until Cells(r.Row, colCheck) = ""
strarray = strarray & IIf(colCheck > 4, ",") & """" & Cells(r.Row, colCheck).Value & """"
colCheck = colCheck + 1
Loop
ActiveWorkbook.Sheets(strarray).Select
ActiveWorkbook.SelectedSheets.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:=Mypath & ws.Range("C" & r.Row).Text & ".pdf", _
Quality:=xlQualityStandard, IncludeDocProperties:=True, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
End If
Next r
End Sub
You can use a regular array rather than the Array() function to create the array. Then you can loop through the cells that contains sheet names and only add them if they're not blank. Here's an example.
Sub PDF_maken()
Dim ws As Worksheet
Dim lLastRow As Long
Dim rMap As Range
Dim sPath As String
Dim aSheets() As String
Dim lShCnt As Long
Dim rSh As Range
Set ws = ActiveWorkbook.Worksheets("Printlist")
lLastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
For Each rMap In ws.Range("B2:B" & lLastRow).Cells
'Make sure there's a path
If Not IsEmpty(rMap.Value) Then
sPath = ws.Range("B" & rMap.Row).Text
're-dimension an array to hold all the sheet names
ReDim aSheets(1 To Application.WorksheetFunction.CountA(rMap.Offset(, 2).Resize(1, 8)))
'reset the counter
lShCnt = 0
'loop through all the cells that might have a sheet name
'and add them to the array
For Each rSh In rMap.Offset(, 2).Resize(1, 8).Cells
If Not IsEmpty(rSh.Value) Then
lShCnt = lShCnt + 1
aSheets(lShCnt) = rSh.Text
End If
Next rSh
ActiveWorkbook.Sheets(aSheets).Select
ActiveSheet.ExportAsFixedFormat xlTypePDF, sPath & rMap.Offset(0, 1).Text & ".pdf"
End If
Next rMap
ws.Select
End Sub
If you get Error 9: Subscript Out of Range there are three things to check:
The first one is that you spelled a sheet name wrong. Make sure there are no spaces or other funny business that makes it look like you have a good sheet name and you don't.
Next, make sure you qualify all of your references back to the workbook level. Depending on where your code is, unqualified references can point to different places. Don't ever use Sheets(). Always use ThisWorkbook.Sheets() or some other workbook reference. That will make sure you're not trying to access a sheet in a workbook that you didn't intend to.
Finally, you can get that error if you pass numbers to Sheets because your sheet names are numbers. Or rather they look like numbers, but they're really text. sheets(array(1234,4567)).select is different than sheets(array("1234","4567")).select. You have to pass strings to Sheets or you'll get that error. Kind of. You can pass numbers, but it will Select the sheets based on their index numbers rather than their names. That's why you have to be extra careful when your sheet names look like numbers.
Do a similar loop,
something like
colCheck=4
do until cells(r.row,colCheck)=""
strArray=strarray & iif(colCheck>4,",","") & cells(r.row,colCheck).value
colCheck=colCheck+1
loop
then you'll get something like a,b,c I've not tested this, so may need some tweaking. I'll revisit in a moment.
I'm trying to get data posted from a non-contiguous range into a row in a separate sheet. Before I built the non-contiguous range, this code worked perfectly. I've tried several things to loop through, but nothing I tried will work. It won't copy the ranged data as it sits. It's been years since I've actually done any coding and my re-learning curve seems to be holding me back.... the logic just isn't coming to me. Help!
Sub UpdateLogWorksheet()
Dim historyWks As Worksheet
Dim inputWks As Worksheet
Dim nextRow As Long
Dim oCol As Long
Dim myCopy As Range
Dim myTest As Range
Dim myData As Range
Dim lRsp As Long
Set inputWks = Worksheets("Input")
Set historyWks = Worksheets("DataEntry")
oCol = 3 'order info is pasted on data sheet, starting in this column
'check for duplicate VIN in database
If inputWks.Range("CheckVIN") = True Then
lRsp = MsgBox("VIN already in database. Update record?", vbQuestion + vbYesNo, "Duplicate VIN")
If lRsp = vbYes Then
UpdateLogRecord
Else
MsgBox "Please change VIN to a unique number."
End If
Else
'cells to copy from Input sheet - some contain formulas
Set myCopy = inputWks.Range("VehicleEntry") 'non-contiguous named range
With historyWks
nextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
End With
With inputWks
'mandatory fields are tested in hidden column
Set myTest = myCopy.Offset(0, 2)
If Application.Count(myTest) > 0 Then
MsgBox "Please fill in all the cells!"
Exit Sub
End If
End With
With historyWks
'enter date and time stamp in record
With .Cells(nextRow, "A")
.Value = Now
.NumberFormat = "mm/dd/yyyy hh:mm:ss"
End With
'enter user name in column B
.Cells(nextRow, "B").Value = Application.UserName
'copy the vehicle data and paste onto data sheet
myCopy.Copy
.Cells(nextRow, oCol).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
'clear input cells that contain constants
Clear
End If
End Sub
This is an example to explain how to achieve what you want. Please amend the code to suit your needs.
Let's say, I have a Sheet1 which looks like as shown below. The colored cells make up from my non contiguous range.
Now paste the code given below in a module and run it. The output will be generated in Sheet2 and Sheet3
Code
Sub Sample()
Dim rng As Range, aCell As Range
Dim MyAr() As Variant
Dim n As Long, i As Long
'~~> Change this to the relevant sheet
With Sheet1
'~~> Non Contiguous range
Set rng = .Range("A1:C1,B3:D3,C5:G5")
'~~> Get the count of cells in that range
n = rng.Cells.Count
'~~> Resize the array to hold the data
ReDim MyAr(1 To n)
n = 1
'~~> Store the values from that range into
'~~> the array
For Each aCell In rng.Cells
MyAr(n) = aCell.Value
n = n + 1
Next aCell
End With
'~~> Output the data in Sheet
'~~> Vertically Output to sheet 2
Sheet2.Cells(1, 1).Resize(UBound(MyAr), 1).Value = _
Application.WorksheetFunction.Transpose(MyAr)
'~~> Horizontally Output to sheet 3
Sheet3.Cells(1, 1).Resize(1, UBound(MyAr)).Value = _
MyAr
End Sub
Vertical Output
Horizontal Output
Hope the above example helps you in achieving what you want.