Running a procedure based on cell values in another workbook - vba

I have six different forms, all of which contain the same information but in different places. These forms are sent to me by other parties and once I receive them, I open the file, determine which form I am dealing with, then run the appropriate transposition macro to upload the information to my summary workbook.
I would like to be able to check cells B4, B8, B10, B15 and B20 to ascertain what form I am dealing with, then have the appropriate transposition macro run on its own.
Can someone please help me set this up?
Right now I have the following:
' I use the file path to identify the form that I want to copy information from
Dim FilePath As String
Dim InputTemplate As Workbook
Dim UploadForm As Workbook
Dim Analysis As Worksheet
Dim supplierdata As Worksheet
Dim TemplateType
Set UploadForm = ActiveWorkbook
FilePath = UploadForm.Sheets("Summary").Range("D4").Value
Set InputTemplate = Workbooks.Open(FilePath)
Set Analysis = UploadForm.Sheets("Analysis")
Set supplierdata = InputTemplate.Sheets("Supplier Input Template")
How do I say that if B4.value=Company Name, B8.value=Date, B10.value = Currency... then run the correct transposition macro?

The most-condensed you could do it might be something like:
'....
Set supplierdata = InputTemplate.Sheets("Supplier Input Template")
With supplierdata.Columns(2)
If .Cells(4).value = "Company Name" And .Cells(8).Value="Date" _
And .Cells(10).Value = "Currency" Then
'handle this type of form
End If
End With
If you have many of these types of checks to perform, then you could consider using a "metadata-driven" approach, where you list on a worksheet the Ranges and the corresponding content, and loop over that information to detect the type of report. That would be more coding up-front but easier ongoing maintenance once you have it set up.

Related

Worksheet.Select switching screens excel VBA

I currently have 3 sheets: Input, Process, Output and a macro that uses values displayed on the input sheet and various stores on the process sheet. The problem is when the user presses a submit button linked to the macro on the input page the sheet switches to the Process sheet before displaying the Output sheet. I understand that this is because of this line of code:
Worksheets("Process").Select
However whenever I remove it from the macro everything goes madly out of range. Is there any way of selecting a sheet without actually visually moving to it? I need the macro to do its thing and then simply display the output sheet. Thanks in advance!
As #Jeeped stated and referenced, avoid using Select and Activate, in addition it is safer to qualify references.
For example you can use Range("A1").Value to get a value of the cell A1 in the currently active worksheet, but what if the user didn't have that sheet active at the time or another proc had moved the view? you could get the value of cell A1 from potentially any worksheet.
It would be best to create a reference to the worksheet and then send all your work through it, this way you do not need to change the active worksheet and there is no ambiguity about where the range values are coming from.
For example: -
Option Explicit
Dim WkSht_I As Worksheet 'Input
Dim WkSht_P As Worksheet 'Process
Dim WkSht_O As Worksheet 'Output
Public Sub Sample()
Set WkSht_I = ThisWorkbook.Worksheets("Input")
Set WkSht_P = ThisWorkbook.Worksheets("Process")
Set WkSht_O = ThisWorkbook.Worksheets("Output")
MsgBox "Input A1 = " & WkSht_I.Range("A1").Value
MsgBox "Process A1 = " & WkSht_P.Range("A1").Value
MsgBox "Output A1 = " & WkSht_O.Range("A1").Value
Set WkSht_O = Nothing
Set WkSht_P = Nothing
Set WkSht_I = Nothing
End Sub
Converting your procedures to this method should be safer and clearer and you can set the active sheet just once for it to show content while the others or being worked on.
#Gary's method is the best method to go with when you are working with multiple worksheets.
If you are working with only two sheets, (Considering you have activesheet and target sheet) I am going to recommend
With Worksheets("Process")
Debug.Print .Range("A1")
Debug.Print Range("A1")
End With
Notice "." infront of Range.
The "." indicates that it is part of With
In other words, .Range("A1") is same as Worksheets("Process").Range("A1")
Because second Range("A1") does not have "." it is same as Activesheet.Range("B1") even it's inside of the With-End
If the activesheet is Process Then the out put will be same
But when you select worksheet other than Process, because activesheet changed, the output will be different.
This will avoide using Select which changes the activesheet

Copying Data from External workbook based on headers not in order to another workbook

I hope this is the right place to ask this question as I am on the verge of going crazy. I am so rusty and I have zero experience with VBA (only with C++, java)
The problem:
I am trying to copy data from one workbook to another.
Lets say I have a workbook (called DATA) with several worksheets filled with data. Each column of data has a unique heading (all headings on the same row).
On the other hand I have another workbook (called REPORT) with one worksheet that contains only the heading of the data (in one row). They are not in the same order as in DATA workbook. For example I have 3 headings in REPORT worksheet that can be found in different worksheets in DATA workbook.
I need to loop through all the worksheets in the DATA workbook and copy paste the whole column to the REPORT worksheet when the same heading is found.
This image may help to understand. Explanation
Thanks ALOT for your help in advance. I have searched alot for this code but found similar stuff but didnt manage to understand any .
First attempt at doing it, but getting an error of Run-time error '1004'.
Any help?
Dim MyFile As String
Dim ws As Worksheet
''Workbook that contains one worksheet with all the headings ONLY NO DATA
Dim TargetWS As Worksheet
Set TargetWS = ActiveSheet
Dim TargetHeader As Range
''Location of Headers I want to search for in source file
Set TargetHeader = TargetWS.Range("A1:G")
''Source workbook that contains multiple sheets with data and headings _
not in same order as target file
Dim SourceWB As Workbook
Set SourceWB = Workbooks("Source.xlsx")
Dim SourceHeaderRow As Integer: SourceHeaderRow = 1
Dim SourceCell As Range
''Stores the col of the found value and the last row of data in that col
Dim RealLastRow As Long
Dim SourceCol As Integer
''Looping through all worksheets in source file, looking for the heading I want _
then copying that whole column to the target file I have
For Each ws In SourceWB.Sheets
ws.Activate
For Each Cell In TargetHeader
If Cell.Value <> "" Then
Set SourceCell = Rows(SourceHeaderRow).Find _
(Cell.Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
SourceCol = SourceCell.Column
RealLastRow = Columns(SourceCol).Find("*", LookIn:=xlValues, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
If RealLastRow > SourceHeaderRow Then
Range(Cells(SourceHeaderRow + 1, SourceCol), Cells(RealLastRow, _
SourceCol)).Copy
TargetWS.Cells(2, Cell.Column).PasteSpecial xlPasteValues
End If
End If
End If
Next
Next
Your question didn't specify what part of the problem you're actually stuck on, so I'll assume you don't know how to start. Note that nobody on here is going to provide you with the full working solution to your problem - that's upto you to figure out.
A few tips to get you to start working:
The first question you're going to ask yourself with problems involving multiple workbooks is typically going to be which workbook am i going to attach my macro to?
In your case, the REPORT Workbook looks like a saner option, since you probably want someone to be clicking on something in the report in order to generate it. You could also argue the other way around though.
Once you have chosen where to put your VBA, you have to establish a reference to the other workbook.
You either have to load the other Excel file from disk using Workbooks.Open, or have both Workbooks be open at the same time in your Excel Instance, which I'd recommend for you because it's easier. In this case simply establish the reference using the Workbooks object.
Dim exampleRefToDATA As Workbook: Set exampleRefToDATA = Workbooks("data.xlsx") ' or index
Then, cycle through each Worksheet
using something like For Each ws As WorkSheet In exampleRefToDATA.WorkSheets as your For Loop
In that Loop, loop through the first column using something like
For Each allName As Range In ws.Range(... for you to figure out ...)
In this Loop, you'll have to look if that name is in your REPORTS sheet by doing another loop like
For Each thisName As Range in Range(... seriously, there's enough on stackoverflow on how to properly iterate over the used range of a row ...)
Note how this Range() call is Equivalent to ActiveWorkbook.ActiveWorkSheet.Range, which is your Reports sheet.
Then just check for equality and copy the row over if necessary. Again, copying a row has also been covered here before.
Hope this was helpful for you.

Excel Vba - Calling a sheet with a variable sheet name

I've been coding in VBA for some time, but this one has really stumped me.
I'm creating a workbook which creates technical certificates for machines. We have varying templates depending on the machine type and I am attempting to get my code to select the correct sheet from a user input and then populate the sheet. FYI these template sheets will be hidden and the user can only interact with the userforms.
Heres the code that is failing:
Machine = MachineType.Text '<-- input from userform, for example Machine = "Vertex 251"
Set wsCopy = ThisWorkbook.Sheets(Machine) '<--- select that machine's sheet
wsCopy.Copy '<--Run time Error 1004: Method copy of object_worksheet failed
I've tried numerous different types including just sheets(machine).copy or
Sheets(machine).activate
Activesheet.copy
but nothing has worked so far - I cannot tell if I am doing something fundamentally wrong.
Any help would be be appreciated.
Cheers.
You must unhide the sheet before copying it (at least to a new workbook as lturner notes) - you can then re-hide it
Dim shtTemplate as Worksheet, sheetWasHidden As Boolean
Set shtTemplate = ThisWorkbook.Sheets(Machine)
'handle the case where the sheet to be copied is Hidden
If shtTemplate.Visible = xlSheetHidden Then
shtTemplate.Visible = xlSheetVisible
sheetWasHidden = True
End If
shtTemplate.Copy
If sheetWasHidden Then shtTemplate.Visible = xlSheetHidden 're-hide if needed
When you have the worksheet object and use the Copy method, Excel seems to be making assumptions (or not) about where you want to put the new sheet. I pretty much always use the After option to define where the new sheet should go.
Option Explicit
Sub test()
Dim wsCopy As Worksheet
Set wsCopy = ActiveSheet
wsCopy.Copy After:=wsCopy
End Sub

How to access a closed Excel Workbook using vlookup vba

I'm trying to create a Excel VBA macro that uses VLOOKUP to access a range of cells in a closed workbook. I'm not too good at using the VBA editor, but it doesn't seem to show a lot of useful information about errors.
Sub WorkBookWithData()
Dim currentWb As Workbook
Set currentWb = ThisWorkbook
Dim currentWs As Worksheet
Set currentWs = currentWb.Sheets(1)
Dim strFormula As String
strFormula = "=VLOOKUP(currentWs.Range("B2"),'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
currentWs.Range("C2").Formula = strFormula
End Sub
Excel VBA editor is hanging up on the "strFormula = "=VLOOKUP..." section.
Thanks
Reference from Siddharth Rout's comments.
The main problem in your code is this line:
strFormula = "=VLOOKUP(currentWs.Range("B2"),'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
because of this code currentWs.Range("B2"). We know that you want to indicate Range("B2") of Current Sheet(same sheet). So, you can use as follow:
strFormula = "=VLOOKUP(B2,'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B‌​222,2,false)"
Why? It can use just B2 because you set formula to a cell which is in the same sheet. So, it is not need to indicate the Sheet Name.
And If you want to set a cell which is from other sheet, you need to indicate Sheet Name in that case. So, should use as follow:
strFormula = "=VLOOKUP(" & currentWs.name & "!B2,'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
This looks nothing like what I had previously, but it works.
Sub Check_Master_Values()
Dim newCurWb As Workbook
Set newCurWb = Workbooks(2)
newCurWb.Activate
newCurWb.Sheets(1).Range("C2").Formula = "=VLOOKUP(B2,'Macintosh HD:Users:myself:Documents:[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!$A$1:$B$269,2,FALSE)"
End Sub
In my first attempt, I didn't follow the chain of assignments from workbook, to sheets, to ranges. As you can see in this code, I Dim a new Workbook - then the big ah-ha moment, I needed to assign it to the correct open workbook. Then, I activated the workbook, and finally accessed the Sheets object and Range.
I also know now that my workbook selection number will vary depending on how many other workbooks are open. The ThisBook didn't work because somehow in the process, the workbook that ThisBook referenced, changed. That is probably also why my initial code didn't work, in addition to the improper coding in the VLOOKUP.
It would be good if there was a way to specify which workbook on the fly.
Thanks to everyone who gave help on the VLOOKUP part.

Excel 2003(VBA) - Custom Identifier / Function / UDF

I'm currently rewriting a small stock system for my work, and trying to speed up the program as it's dog slow and I have only been doing VBA for 2 weeks now.
In Excel 2003 Edition.
My issue (I think) is creating a identifier(s).
I have two and they are as follows:
Dim QuickView As String
QuickView = ActiveWorkbook.Range("a1:c200").Copy
Dim Stock As String
Stock = ActiveWorkbook.Range("c1:c200").Copy
My users currently select a file(WORKBOOK) from an open dialogue and I am importing the data in the ranges specified.
However, when I come to call these functions I get "Object does not support this property or method".
im unsure if this should be a UDF, as i can't see anywhere where you can write your own VBA function opposed to write a function in VBA for Excel to use.
In your two examples, both "QuickView" and "Stock" should be variants, not strings.
Dim Stock As Variant
Stock = ActiveWorkbook.Range("c1:c200").Copy
Remember, you do NOT need to assign ranges to a variable in order to copy (or cut) cell values to another location. Instead, you can do it like this:
ActiveWorkbook.Sheets("Sheet1").Range("c1:c200").Copy
ThisWorkbook.Sheets("Sheet1").range("c1")
The convention is copy_from [SPACE] put_it_here.
Note: In my example above, the values would be copied into Sheet1 of the workbook that contains the running code. The workbook running the VBA is always ThisWorkbook.
As #timbur said, you can copy a range without assigning it first. If you want to assign it, the variable must be of type Range (or Variant) and you must assign using Set, like any object assign.
Dim stock as Range 'or Variant, but Range is better
Set stock = ActiveWorkSheet.Range("c1:c200")
'copy, and optionally paste at once
stock.Copy Destination:=ThisWorkbook.Sheets("Sheet1").range("c1")
eSolved it guys, thanks for your answers :-D
Sub Button1_Click()
Dim FileOpened As Boolean ' Holds True or False value
Dim SourceRange As Range
Dim TargetRange As Range
Dim MasterWorkbook As Workbook
Dim Row As Integer
' Remember the current workbook we are clicking the button from.
Set MasterWorkbook = ActiveWorkbook ' Use Set = for all complex types.
' Identify file to open.
ChDrive "C:"
ChDir "c:\"
On Error Resume Next ' Temporarily ignore errors in situation when user says no to opening the same master file a second time.
FileOpened = Application.Dialogs(xlDialogOpen).Show
On Error GoTo 0 ' Reinstates normal error reporting.
' Don't process the file if the user cancels the dialog.
If FileOpened Then
' The opened file automatically becomes the new active workbook and active worksheet.
Set SourceRange = ActiveSheet.Range("c1:c394")
Set TargetRange = MasterWorkbook.ActiveSheet.Range("b1:b394")
' Copy cell values one at a time from the source range to the target range.
For Row = 1 To 394
TargetRange.Cells(Row, 1).Value = SourceRange.Cells(Row, 1).Value
Next
ActiveWorkbook.Close
' Set background colour of target range.
TargetRange.Select
With Selection.Interior
.ColorIndex = 6
.Pattern = xlSolid
End With
' Tell Excel to recalculate only those formulas which use the target values.
TargetRange.Dirty
End If
End Sub
For those interested in this code :
User selects a file from nominated directory then selects the nominated range "c1:c394" from that file and pasts it into the "sheet1".
Bypassing clipboard and updates any formulas affected by the added values.