vLookup error for VBA in Excel - vba

I have a form that has a list of items from which it unhides the relevant item-sheet based on the form selection. Due to the length of item name, each item is assigned an ID. The vlookup function is meant to retrieve the relevant ID based on the matching of names in another sheet.
The code is as follows.
The fundName value being passed in is "AX - Arnold Xchange Securities (USD)".
The fundID is located on the 5th column of the array being searched.
The fundID definitely exists
The problem here is that it gives me a runtime error where it cannot get the vLookup property of the function class. Error 1004
Private Sub FundLookupImage_Click()
Dim fundName As String
Dim fundSheetName As String
Dim ws As Worksheet
Set ws = Worksheets("DownloadTable")
MsgBox ws.UsedRange.EntireRow.Count
fundName = Me.FundList.Value
fundName = """" & fundName & """"
MsgBox fundName
fundSheetName = CStr(Application.WorksheetFunction.VLookup(fundName, ws.Range("A:F"), 5, True))
MsgBox fundSheetName
Unload Me
End Sub
I've tested the vLookup method on excel itself and it retrieves the correct ID

Using VLookup makes me crazy always when I have to use it, please try this:
DIM searchResult AS variant
searchResult = 0
On Error Resume Next
searchResult = Application.WorksheetFunction.VLookup(fundName, ws.Range("A:F"), 5, 0)
fundSheetName = CStr(searchResult)

Related

VBA Form - Vlookup cell and assign value to that cell

Encountering an issue in a VBA regarding vlookup function.
I have 2 comboboxes and 6 Textboxs for user input.
I want to use a vlookup (or index,Match(),Match()) to look up a cell in a data table and assign the values from the textboxes to these cells.
When I run the code for what I believe should work, it is returning object errors.
Private Sub CommandButton2_Click()
Dim MonthlyTable As Range
Set MonthlyTable = Sheets("DATA Monthly").Range("A6:AE400")
Dim ColumnRef As Range
Set ColumnRef = Sheets("Drivers").Range("N11")
' Assign CB2 value to M11 cell reference so it can be converted to a column ref in N11.
Sheets("Drivers").Range("M11").Value = ComboBox2.Value
Dim CB1Value As String
CB1Value = "Joiners" & ComboBox1.Value
Dim CB2Value As String
CB2Value = ComboBox2.Value
MsgBox CB1Value & " " & CB2Value
Dim tb1value As Range
tb1value = Application.WorksheetFunction.VLookup(CB1Value, MonthlyTable, ColumnRef, False)
tb1value.Value = TextBox1.Value
Unload Me
End Sub
I am at a loss for what to do here as I feel like it should be this simple!
Thanks in advance.
Edit. Further digging indicates that you cannot select a cell you are vlookup'ing as this commands only returns a value it does not actually select the cell for my intents and purposes.
not really clear to me you actual aim, but just following up your desire as stated by:
I want to use a vlookup (or index,Match(),Match()) to look up a cell
in a data table and assign the values from the textboxes to these
cells
you may want to adopt the following technique:
Dim tb1value As Variant '<--| a variant can be assigned the result of Application.Match method and store an error to be properly cheeked for
tb1value = Application.Match(CB1Value, MonthlyTable.Column(1), 0) '<--| try finding an exact match for 'CB1Value' in the first column of your data range
If Not IsError(tblvalue) Then MonthlyTable(tb1value, columnRef.Value).Value = TextBox1.Value '<--| if successful then write 'TextBox1' value in data range cell in the same row of the found match and with `columnRef` range value as its column index
Excel uses worksheet functions to manipulate data, VBA has different tools, and when you find yourself setting cell values on a sheet via VBA so that some worksheet function can refer to them it is time to look for a true VBA solution. I suggest the following which, by the way, you might consider running on the Change event of Cbx2 instead of a command button.
Private Sub Solution_Click()
' 24 Mar 2017
Dim MonthlyTable As Range
Dim Rng As Range
Dim Lookup As String
Dim Done As Boolean
Set MonthlyTable = Sheets("DATA Monthly").Range("A2:AE400")
' take the lookup value from Cbx1
Lookup = ComboBox1.Value
Set Rng = MonthlyTable.Find(Lookup)
If Rng Is Nothing Then
MsgBox Chr(34) & Lookup & """ wasn't found.", vbInformation, "Invalid search"
Else
With ComboBox2
If .ListIndex < 0 Then
MsgBox "Please select a data type.", vbExclamation, "Missing specification"
Else
TextBox1.Value = MonthlyTable.Cells(Rng.Row, .ListIndex + 1)
Done = True
End If
End With
End If
If Done Then Unload Me
End Sub
There are two points that need explanation. First, the form doesn't close after a rejected entry. You would have to add a Cancel button to avoid an unwanted loop where the user can't leave the form until he enters something correct. Note that Done is set to True only when the search criterion was found And a value was returned, and the form isn't closed until Done = True.
Second, observe the use of the ListIndex property of Cbx2. All the items in that Cbx's dropdown are numbered from 0 and up. The ListIndex property tells which item was selected. It is -1 when no selection was made. If you list the captions of your worksheet columns in the dropdown (you might do this automatically when you initialise the form) there will be a direct relationship between the caption selected by the user (such as "Joiners") and the ListIndex. The first column of MonthlyTable will have the ListIndex 0. So you can convert the ListIndex into a column of MonthlyTable by adding 1.
I think it is better to use "find" in excell vba to select a cell instead of using vlookup or other methods.

Find invalid data validation cells

Description:
I have created a custom dropdown data validation list where I can choose among several values. These values on the dropdown list changes as I need (are defined in a worksheet column X).
Problem:
My problem occurs when I choose one of those values, let say Y, from the dropdown list and then I update the data validation by removing the last inserted value (deleted the Y value from column X). By doing this the value Y present in the worksheet is no longer valid so I would like to know if there is a way to obtain a list (array or string) of cells with the invalid data.
What I have done/thought so far:
I have searched in several sites and read similar questions but I cannot find anything usefull. I thought about looping all the cells and check if the value is valid but since I have a huge amount of data I think that it is not the best approach.
Since Excel already mark these invalid data with a red circle maybe it could be possible to get the address of those marked cells?
Thanks in advance!
The correct way to obtain the invalid cells in a worksheet is using Cells.SpecialCells(xlCellTypeAllValidation).
By using some information present in Microsoft KB213773 (Q213773) - "How to create data validation circles for printing in Excel" a similar Sub can be used to loop all invalid cells and then change their values (or mark them to future edit).
Sub CorrectInvalidValues()
Dim data_range As Range
Dim invalid_cell As Range
Dim count As Integer: count = 0
Dim nr_invalid As Integer: nr_invalid = 0
Dim new_value As String
'If an error occurs run the error handler and end the procedure
On Error GoTo errhandler
Set data_range = Cells.SpecialCells(xlCellTypeAllValidation)
On Error GoTo 0
' Loop through each cell that has data validation and gets the number of invalid cells
For Each invalid_cell In data_range
If Not invalid_cell.Validation.Value Then
nr_invalid = nr_invalid + 1
End If
Next
' Editing each value
For Each invalid_cell In data_range
If Not invalid_cell.Validation.Value Then
count = count + 1
Application.Goto reference:=invalid_cell, Scroll:=True
new_value = Application.InputBox("Please insert a correct value.", "Invalid Data " & count & "/" & nr_invalid)
If Not (new_value = "False") Then
invalid_cell.Interior.ColorIndex = 0
invalid_cell.Value = new_value
Else
invalid_cell.Interior.Color = RGB(255, 0, 0)
invalid_cell.Value = "<PLEASE EDIT>"
End If
End If
Next
Exit Sub
errhandler:
MsgBox "There are no cells with data validation on this sheet."
End Sub

Adding values to a combobox based on another value VBA

I am currently trying to get a combobox to add items based on another combobox value, but am coming unstuck.
The following is the code I have so far - through trial and error I have got to this stage, although this is still giving me a "1004" error relating to the last line of the code. Is there a better way of writing this to get the same result?
Private Sub ProductInfo1_Change()
Dim strName As String
Dim strNameProductAllData As String
Dim strNameProductName As String
Dim strNameProductDescription As String
strName = Replace(OrderForm1.OrderFrm3.Value, " ", "")
sheet = "strName"
strNameProductName = Replace(strName, " ", "") & "productname"
strNameProductDescription = Replace(strName, " ", "") & "productdescription"
Me.ProductInfo2 = Application.WorksheetFunction.Index(Sheets(strName).Range(strNameProductDescription), Application.WorksheetFunction.Match(ProductInfo1.Value, Sheets(strName).Range(strNameProductName), 0))
End Sub
You are assigning to the wrong object.
You are trying to set a combobox, ProductInfo equal to a range.
What you want to do is use the "RowSource" property of the combobox
For example:
Me.ProductInfo2.RowSource = "mySheet!$A$1:$A$10"
This would make the choices for the ProductInfo2 combobox the items in cells A1-A10.
It is unclear what you are trying to get with the Match/Index Worksheet functions. If the contents of the cell have a range, then just use the contents to be equal to this rowsource. So for instance, if the column that represents "strNameProductDescription" has the range "myRange" in it, then your code can simply be modified to put this into the RowSource property. If it contains some other piece of information, then you need to construct the range you are looking for so that it would be similar to the line shown above. If myRange is a range on your worksheet, then the code,
Me.ProductInfo2.RowSource = "myRange"
will work.

dynamically select sheet from the inputprompt and print to a file

i have 3 sheets in my workbook namely sheet1 ,sheet3 and sheet2 when i enter a values from in the inputpromt say (eg:1,2 ) i split it and store it in an array it must dynamically select the sheet1 and sheet2 and print values to a file.
i have done a pseudo below can any one
Sub example()
Dim Ran As Range
Dim cnt as String
Open "D:\temp\test.txt" For Output As #1
Dim myarray() As String
Dim holder As String
dim ab as Strig
ab="this is sample data"
holder = InputBox("Enter your choice eg:1,2")
myarray = Split(holder, ",")
Dim name, country,birth As String
For i = 1 To UBound(myarray)
If i = 1 Or i = 2 Then
name = Sheets(i).Range("Z12").Value
country= Sheets(i).Range("PQ26").Value
birth = Sheets(i).Range("ab24").Value
ab=ab & name & country & birth
Print #1, ab
End If
Next i
end Sub
****in the inputbox if i give value as 1,2 then it must select values from sheet 1 and sheet2****
I am guessing you that you are trying to understand InputBox and how to split a string such as “1, 2” and process the separate values as sheet numbers.
Sheet numbers mean nothing to the user so I do not believe this is a good approach. You need to offer the user a list of worksheet tabs from which they can select.
There is InputBox and Application.InputBox. These are different and I do not like either. They come from the earliest versions of VB and were probably originally a direct match to MS-DOS’s console input. With one exception, there are much better approaches. The one exception is the ability to input a range with Application.InputBox for which I do not know a convenient alternative.
In the code below I use InputBox. You may think I have overdone the validation but what if the user enters “A”? Your code would assume “A” was a sheet number but Excel would assume it was a worksheet name and stop execution with a subscript error. You must check for any error that will cause your code to stop with a run-time error.
Instead of either InputBox you should use a User Form. There are on-line tutorials to get you started. With a User Form you have several choices including:
A List box, with multiple selection enabled, containing the names of every permitted worksheet.
A column of radio buttons, one per permitted worksheet. These would be unlinked so the user could select several.
A command button for each permitted worksheet which the user could click in turn.
All of these choices are much user-friendlier than InputBox.
Step through the code below with F8 and study what it does. Come back with questions if necessary but the more you can understand on your own the faster you will develop.
Option Explicit
' Please indent your macros consistently. This makes them much easier ri read
Sub example()
Dim Ran As Range
Dim cnt As String
Dim myarray() As String
Dim ab As String
' Variables I have added or which are replacements for yours.
Dim Answer As String
Dim AllValuesGood As Boolean
Dim InxMA As Long
Dim InxSht As Long
Dim Question As String
' I like to keep all my Dim statements together at the top.
' This makes them easier to find.
Dim name, country, birth As String
' I have output to the Immediate window which is simpler when
' experimenting.
'Open "D:\temp\test.txt" For Output As #1
Question = "Enter your choice eg: ""1"" or ""1,2"""
' You omitted the code to check the Answer
Do While True
Answer = InputBox(Question, "Experiment with Input box")
' Have a string but user could have typed anything
If Answer = "" Then
' Cannot tell if user has clicked Cancel or if user clicked Return
' before entering value. Have to assume Cancel
Debug.Print "User clicked Cancel"
Exit Sub
Else
AllValuesGood = True ' Assume good answer until find otherwise
myarray = Split(Answer, ",")
For InxMA = 0 To UBound(myarray)
If IsNumeric(myarray(InxMA)) Then
InxSht = Val(myarray(InxMA))
If InxSht < 1 Or InxSht > 2 Then
' Sheet number outside permitted range
AllValuesGood = False
Exit For
End If
Else
' Non-numeric sheet number
AllValuesGood = False
'Debug.Assert False
Exit For
End If
Next
End If
If AllValuesGood Then
' Have good answer. Exit Do-Loop to print sheets
Exit Do
Else
' An invalid sheet number has been found
Question = "Click cancel to exit or enter ""1"" or ""2"" or ""1, 2"""
' Loop to repeat Input
End If
Loop ' Until have good answer
' If get here Answer is a list of good sheet number
For InxMA = 0 To UBound(myarray)
InxSht = Val(myarray(InxMA))
' I have not created sample worksheets with data in Z12, PQ26 and ab24
' but this shows the code you need
'With Worksheets(InxSht)
' name = .Range("Z12").Value
' country = .Range("PQ26").Value
' birth = .Range("ab24").Value
'Next
name = "Name" & InxSht
country = "Country" & InxSht
birth = "Birth" & InxSht
' Have to initialise ab here because need new value per sheet
ab = "this is sample data"
ab = ab & name & country & birth
Debug.Print ab
' The value of ab will be messy because you have no spaces between words.
'Print #1, ab
Next InxMA
End Sub

Error 9: Subscript out of range

I have a problem in excel Vba when I try to run this code, I have an error of subscript out of range:
Private Sub UserForm_Initialize()
n_users = Worksheets(Aux).Range("C1").Value
Debug.Print Worksheets(Aux).Range("B1:B" & n_users).Value
ListBox1.RowSource = Worksheets(Aux).Range("B1:B" & n_users).Value
ComboBox1.RowSource = Worksheets(Aux).Range("B1:B" & n_users).Value
ComboBox2.RowSource = Worksheets(Aux).Range("B1:B" & n_users).Value
End Sub
And Debug.Print works well, so the only problem is in Range("B1:B" & n_users).Value.
If the name of your sheet is "Aux", change each Worksheets(Aux) reference to Worksheets("Aux"). Unless you make Aux a string variable, for example:
Dim Aux As String
Aux = "YourWorksheetName"
n_users = Worksheets(Aux).Range(C1).Value
you must use quatations around sheet references.
Firstly, unless you have Aux defined somewhere in the actual code, this will not work. The sheet-name reference must be a string value, not an empty variable (which ARich explains in his answer).
Second, the way in which you are trying to populate the rowsource value is incorrect. The rowsource property of a combobox is set using a string value that references the target range. By this I mean the same string value you would use in an excel formula to reference a cell in another sheet. For instance, if your worksheet is named "Aux" then this would be your code:
ComboBox1.RowSource = "Aux!B1:B" & n_users
I think you can also use named ranges. This link explains it a little.
I can't see how you can get an Error 9 on that line. As others have pointed out repeatedly, the place you'll get it is if the variable Aux doesn't have a string value representing the name of a worksheet. That aside, I'm afraid that there is a LOT wrong with that code. See the comments in the below revision of it, which as near as I can figure is what you're trying to get to:
Private Sub UserForm_Initialize()
'See below re this.
aux = "Sheet2"
'You should always use error handling.
On Error GoTo ErrorHandler
'As others have pointed out, THIS is where you'll get a
'subscript out of range if you don't have "aux" defined previously.
'I'm also not a fan of NOT using Option Explicit, which
'would force you to declare exactly what n_users is.
'(And if you DO have it declared elsewhere, I'm not a fan of using
'public variables when module level ones will do, or module
'level ones when local will do.)
n_users = Worksheets(aux).Range("C1").Value
'Now, I would assume that C1 contains a value giving the number of
'rows in the range in column B. However this:
'*****Debug.Print Worksheets(aux).Range("B1:B" & n_users).Value
'will only work for the unique case where that value is 1.
'Why? Because CELLS have values. Multi-cell ranges, as a whole,
'do not have single values. So let's get rid of that.
'Have you consulted the online Help (woeful though
'it is in current versions) about what the RowSource property
'actually accepts? It is a STRING, which should be the address
'of the relevant range. So again, unless
'Range("B1:B" & n_users) is a SINGLE CELL that contains such a string
'(in which case there's no point having n_users as a variable)
'this will fail as well when you get to it. Let's get rid of it.
'****ListBox1.RowSource = Worksheets(aux).Range("B1:B" & n_users).Value
'I presume that this is just playing around so we'll
'ignore these for the moment.
'ComboBox1.RowSource = Worksheets(aux).Range("B1:B" & n_users).Value
'ComboBox2.RowSource = Worksheets(aux).Range("B1:B" & n_users).Value
'This should get you what you want. I'm assigning to
'variables just for clarity; you can skip that if you want.
Dim l_UsersValue As Long
Dim s_Address As String
l_UsersValue = 0
s_Address = ""
'Try to get the n_users value and test for validity
On Error Resume Next
l_UsersValue = Worksheets(aux).Range("C1").Value
On Error GoTo ErrorHandler
l_UsersValue = CLng(l_UsersValue)
If l_UsersValue < 1 Or l_UsersValue > Worksheets(aux).Rows.Count Then
Err.Raise vbObjectError + 20000, , "User number range is outside acceptable boundaries. " _
& "It must be from 1 to the number of rows on the sheet."
End If
'Returns the cell address
s_Address = Worksheets(aux).Range("B1:B" & n_users).Address
'Add the sheet name to qualify the range address
s_Address = aux & "!" & s_Address
'And now that we have a string representing the address, we can assign it.
ListBox1.RowSource = s_Address
ExitPoint:
Exit Sub
ErrorHandler:
MsgBox "Error: " & Err.Description
Resume ExitPoint
End Sub