Use VLOOKUP to pass cell reference to a public variable? - vba

I have a userform that opens on cell change in a column.
That userform contains checkboxes, which all trigger a second userform with a text box which looks up a cell on a hidden sheet for its contents. (The checkbox that's ticked determines which cell the textbox looks for). The user then edits the box, clicks a button, and the new text is written back to the same cell.
This is the VBA for when the checkbox is ticked. It works great. Hooray!
Dim vln As Variant
Dim reta As Worksheet
Set reta = ActiveWorkbook.Sheets("RetailerActivity")
Set vln = ActiveCell.Offset(-1, -3)
UserForm2.TextBox1.Text = Application.WorksheetFunction.VLookup(vln, reta.Range("A1:Z100"), 3, False)
UserForm2.TescoSave.Visible = True
UserForm2.Show
End Sub
When the textbox has been edited, I would like to write it back to the same cell it came from. I figure the easiest way to do that is to have a public variable (as range), and to pass the result of the vlookup into that variable so the second userform can have a line which reads
Private Sub ASave_Click()
publicvariable.Value = TextBox1.Value
userform1.hide
End Sub
Nice and easy, rather than doing a VLookup again. Right?
Either way, I can't seem to set the public variable as the lookup.
Outside of any sub I have
Public bums As Range
And in the code above, after the bit where I've set the text box, I've tried to add the line
Set bums = Application.WorksheetFunction.VLookup(vln, reta.Range("A1:Z100"), 3, False)
But the code errors with a "type mismatch".
If I try
Set bums = Range(Application.WorksheetFunction.VLookup(vln, reta.Range("A1:Z100"), 3, False))
I get method "Range" of object "_global" failed.
I code by cobbling bits off the internet, as you can probably tell, so this is I don't doubt a complete kludge.
Any advice would be super appreciated.

VLookup returns a value, not a Range. You could use Match to find the row and then Cells to get the actual reference - for example:
Dim vMatch
vMatch = Application.Match(vln, reta.Range("A1:A100"),0)
If Not IsError(vMatch) then
Set bums = reta.Cells(vMatch, "C")
else
msgbox "No match for " & vln
Exit Sub
End If
Personally I would also not use a public variable, but create a property for Userform2 to which you can assign the range.

Related

Excel VBA .Find Function changing values in selection

Heya this is probably simple but I cannot figure out what is wrong.
I am trying to do .find for a specific date and change that selection to a user input date.
I have a userform to select a date from a combobox (date1_cbo). The combobox source is linked to dates on a worksheet (Backend). There is a textbox below for writing the new date to change it to (date1_txt). I keep getting an error
object variable or with block variable not set.
I have tried a few options without any luck here is my code:
Dim selection As Range
Dim check As Boolean
'input box validation
check = IsDate(date1_txt.Value)
If check = True Then
'find cell matching combobox
With Worksheets("Backend").Range("A1:A500")
Set selection = .Find(date1_cbo.Value) 'this is the problem
selection.Value = date1_txt.Value
End With
Else
End If
Interestingly .Find returns the range or Nothing. however because the combobox is linked to the cells I am searching through this should never return nothing... I dont understand why the error is occurring.
a variable named as 'selection' is bad coding practice but totally legal. Don't use such names for the sake of clarity.
Error 91 is caused when you are trying to read a property( .value) from null object. your selection variable is null cause date formats on the sheet and combobox are different.
Just convert to date before attempting to find it in sheet.
Set selection = .Find(CDate(date1_cbo.Value)) '/ once again, selection is valid but bad name for variable.
You are using a variable named Selection. VBA uses it as well. Rename your variable to anything else, rewrite your code and it should work. Even Selection1 is quite ok:
Public Sub TestMe()
Dim selection1 As Range
With Worksheets(1).Range("A1:A500")
Set selection1 = .Find("vi")
End With
If Not selection Is Nothing Then
selection1.Value = "some other value"
End If
End Sub
To change multiple values with Find() as here - A1:A10, then some possibility is to do it like this:
Public Sub TestMe()
Dim myRng As Range
With Worksheets(1).Range("A1:A500")
.Range("A1:A10") = "vi"
Set myRng = .Find("vi")
If Not myRng Is Nothing Then
Do Until myRng Is Nothing
myRng.Value = "New value"
Set myRng = .Find("vi")
Loop
End If
End With
End Sub
It is a bit slow, as far as it loops every time and it can be improved, if the range is united and replaced at once.

VBA: ComboBox only showing one item after Workbook_Open event

I am attempting to have a Workbook_Open event populate a controls ComboBox
so that when the user goes to the Worksheet("Benchmarking"), they have a pre-populated list to choose from that includes all the items in the array datesArr.
The problem i am having is, upon opening the spreadsheet and navigating to the Worksheet("Benchmarking"), i am only seeing one item in the drop down list:
If i select that item then the list actually populates:
Desired result:
I want the full list to be available from the first time the user tries to make a selection not just after the ComboBox1_Change event is fired.
Having reviewed numerous post e.g. Sometimes the ActiveX Combobox only shows one row, why? , Populating Combo Box on WorkBook Open I have tried several different approaches including the following in the Workbook_Open event code:
.ListFillRange = "DropDownDates"
.List = DateArrToStrAr
I have also looped the array adding the items to ComboBox1. Each time i get the same 1 visible item in drop down result.
Is someone able to tell me where i am going wrong please?
My current code is
1) ThisWorkbook
Private Sub Workbook_Open()
With Worksheets("Benchmarking").OLEObjects("ComboBox1").Object
.Clear
.List = DateArrToStrArr '
End With
End Sub
2) Worksheet("Benchmarking"):
Private Sub ComboBox1_Change() 'QH 2/11/17
Dim datesArr() As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Lkup")
datesArr = DateArrToStrArr 'function that reads a named range of dates and converts to string to avoid dd/mm becoming mm/dd
If ComboBox1.Value = vbNullString Then ComboBox1.Value = "01/04/2016"
ComboBox1.List = datesArr
'.....other code
End Sub
Notes:
The array datesArr is populated by the function DateArrToStrArr() which reads in a named range of dates "DropDownDates" (workbook scope) and converts them to a string array. This is then assigned to the ComboBox.
DropDownDates is a dynamic named range with formula =OFFSET(Lkup!$F$16,,,Lkup!$M$12,)
Set-up: Excel 2016 64 bit Windows.
Thanks to #CLR for making me think about recalcs. I decided to hack my way around this with the following:
I have added in Worksheet("Benchmarking") a Worksheet_Activate event and removed the Workbook_Open code. This seems to do the trick
Private Sub Worksheet_Activate()
' ComboBox1.Clear
ComboBox1.List = DateArrToStrArr
End Sub

VBA with if case for checkbox in excel

I am having an userform where I have 8 Checkboxes in it.
Each checkbox is assigned to an call function called autofilter.
I would like to have an vba,in such a way that more than one Checkbox is used, then it should Display the result of selected Checkbox.
How can I achieve in VBA. I am struck how i should proceed with this Problem.
Expecting an help from Forum.
This is my autofilter program
Sub autofilter()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Result")
wslr = ws.Cells(Rows.Count, 1).End(xlUp).Row
Set myfilt = ws.Range("A1:AFU" & wslr)
myfilt.autofilter Field:=12, Criteria1:= _
"USA"
End Sub
similarly, i have them for other Locations as well till autofilter7.
Right now, i have the code working in such a way that, if check box 1 is true it calls autofilter1.
I would like to have a VBA, in such a way that, when i select 1 or more checkboxes, it should call their autofilter function together. How can i achieve this ?
[![I have userform with Checkboxes designed like this.in the command button i have the following code,
If CheckBox1.Value = True Then
Call autofilter
End If
similarly, I have it same for other checkboxes.
]1]1
Difficult to answer without all the exact details, but I think you are looking for something like:
In the command button _Click sub code, you should have this:
Edited : notice Dim i as String at the top.
Dim formControl As Control
Dim i As String
'loop through every control in the userform
For Each formControl In Me.Controls
'Test if the control is a checkbox
If LCase(TypeName(formControl)) = "checkbox" Then
If formControl.Value = True Then
'The below is very crude and you should find a better way of getting parameter from checkbox
'The below also assumes you use ONE filterFunction that takes a parameter
'You need to get the number from the checkbox, so take the number from the name of the checkbox
i = Right(formControl.Name, 1) - 1
'myFilterFunction i (Use this only if you have parameterised your function)
'change i to empty string if it was 0.
i = IIf(i = 0, "", i)
'This calls a function represented by the string
Application.Run "myFilterFunction" & i
End If
End If
Next formControl
At the moment, the away you've describe it, the code should work. Replace the name of the function with the name of your autofilter function....

Using relative references to reuse a macro for a control

I'm trying to write an Excel 2007 macro for a coworker, but my VBA skills are pretty basic (pardon the pun). Essentially, what needs to happen is, when a checkbox is clicked, the neighboring cell to the right is filled with the username of the person logged in.
So far, here's the code I've come up with that allows me to do that:
Sub CheckBox1_Click()
Range("J4").Activate
If ActiveCell.Offset(0, 18).Value = True Then
ActiveCell.Offset(0, 1).Value = Environ("UserName")
Else
ActiveCell.Offset(0, 1).Clear
End If
End Sub
Just for the sake of reference, that "ActiveCell.Offset(0,18)" refers to a cell that is linked to the checkbox in question and contains its true/false value.
(EDIT: Also, the reason cell J4 is activated is because in this case, it's the cell containing the ActiveX checkbox)
That works perfectly, but that's not my problem. My problem is this: there are 49 more checkboxes in that row, and three more rows on this sheet, and 45 more sheets in this book. I do NOT want to have to copy paste the same code into a unique macro just to change the active cell. More importantly, as a good programmer, I shouldn't be repeating code like that. How should I write this so that I don't have to refer to a distinct cell every time?
EDIT 2: Holy smokes, Lance just helped me realize I was mistaken. The sheet uses form controls, not ActiveX controls. Greatly sorry, everyone.
While this is easy to do with a Sheet object, it's pretty hard to do with an ActiveX Control object. You can't self-reference the name of an ActiveX Control in its event, unless it's passed to it, and you also can't reference the name of the event subroutine to extract the name, and you can't reference the name of the routine that called a routine.
I also attempted to trigger off of the Worksheet Change and SelectionChange events, but those don't trigger off of a checkbox change, even if it has a LinkedCell that changes
What I finally came up with was the somewhat generic wrapper for the click event, that you'll have to modify the string to match the Checkbox name:
Private Sub CheckBox1_Click()
NameCopy Me, "CheckBox1"
End Sub
and then a Namecopy function that sets the cell -7 to the left of the LinkedCell to the name value.
Public Sub NameCopy(wsheet As Worksheet, cname As String)
If wsheet.OLEObjects(cname).Object.Value = True Then
Range(wsheet.OLEObjects(cname).LinkedCell).Offset(0, -7).Value = Environ("UserName")
End If
End Sub
It's easier with a Forms checkbox, you can use this Macro for all your checkboxes. Just remember to set the Macro to this:
Public Sub NameCopy()
Dim shp As Shape
Set shp = ActiveSheet.Shapes(Application.Caller)
If shp.ControlFormat.Value = xlOn Then
ActiveSheet.Range(shp.ControlFormat.LinkedCell).Offset(0, -7).Value = Environ("UserName")
End If
End Sub
Since you are using form controls, this is really easy. You can use Application.Caller to have the code access the clicked checkbox, and then use it's TopLeftCell property to get where the checkbox is located, and then you can perform whatever operation you want. In your case, something like this I'm guessing:
Sub Checkbox_Click()
With ActiveSheet.CheckBoxes(Application.Caller)
If .Value = 1 Then 'Checkbox is checked
.TopLeftCell.Offset(, 1).Value = Environ("UserName")
Else
.TopLeftCell.Offset(, 1).ClearContents
End If
End With
End Sub

Open Website in excel using ActiveWorkbook.FollowHyperlink

So, this is basically what I'm trying to do. I have a column of employee #'s in a file that's generated from MSSQL. I want to create a function in a cell where the URL would be, http://www.someplace.com/employee.php?ID=Employee#FromCell
So far all of the examples that I've found aren't detailed enough for me to figure out what to do with it. I know this isn't correct, but this is what I ended up with so far
Function openurl(strSKU As String)
ActiveWorkbook.FollowHyperlink Address:="http://www.someplace.com/employee.php?ID=?strSKU=" & strSKU, NewWindow:=True
End Function
I think I'm mixing up methods with functions but I'm not sure where to go with it. I basically want to add it in as a function to make it easier to insert into the column.
I see someone provided you with a work-around for accomplishing this, but I'll give you the method you were asking for (just in case). FYI the intellisense sucks in VBA when referencing OLE objects (i.e., some methods may not appear to belong to the button objects, but they do).
The script below will create the buttons for you automatically, and will send the user to the site you specified when clicked. **I included notes which explain what each line does.
This creates the buttons in columns B and gets the URL parameter from column A:
Sub CreateButtons()
Dim btn As Button 'Create a variable for our button
Application.ScreenUpdating = False 'Speed up the process by disabling ScreenUpdating
ActiveSheet.Buttons.Delete 'Delete existing buttons.
Dim Report As Worksheet 'Create our worksheet variable.
Set Report = Excel.ActiveSheet 'Set our worksheet to the worksheet variable.
Dim t As Range 'Create a variable for the cells we will reference.
For i = 1 To Report.UsedRange.Rows.Count 'This will loop through each row in the used range of our worksheet.
If Report.Cells(i, 1).Value <> "" Then 'If the value of the first cell is not empty, then do the following...
Set t = Report.Range(Cells(i, 2), Cells(i, 2)) 'Assign the cell in the second column of the current row to the cell variable.
Set btn = Report.Buttons.Add(t.Left, t.Top, t.Width, t.Height) 'Create a button and place it in the cell in the second column.
With btn
.OnAction = "openurl" 'Set the button to trigger the openurl sub-routine when it is clicked.
.Caption = Report.Cells(i, 1).Value 'Set the caption of the button to equal the value of the cell in the first column.
.Name = i 'Set the name of the button to equal the row on which it resides. This name will be used in the openurl sub; So don't change it.
End With
End If
Next i
End Sub
This is the macro performed when the user clicks a button:
Sub openurl()
Dim Report As Worksheet 'Create a variable for the worksheet
Set Report = Excel.ActiveSheet 'Assign the worksheet to our variable
Dim i As Integer 'Create a variable for our row number
i = Application.Caller 'Assign name of the button to our row number.
Dim address As String 'Create a variable for our address
address = "http://www.someplace.com/employee.php?ID=?strSKU=" & Report.Cells(i, 1).Value 'Assign the URL to our address variable.
ActiveWorkbook.FollowHyperlink address:=address, NewWindow:=True 'Send the user to the URL you specified (with the URL parameter at the end).
End Sub
BONUS INFO:
Follow the next step to have the entire process done for you automatically:
When you say the current data is populated from a MSSQL database, you probably mean you are pulling the data into Excel using another VBA sub or function. If so, then if you place a script to call the "CreateButtons()" subroutine after the script that pulls the data, this entire process will be done for you automagically. Example:
Sub getEmployeeData() 'This represents your sub that pulls your data from MSSQL
'================================================================
'This represents your script to get your information into Excel.
'================================================================
Call CreateButtons 'This runs the CreateButtons() subroutine.
End Sub
Enjoy!
You can do this without VBA. You can use a formula.
=Hyperlink("http://www.someplace.com/employee.php?ID="&A1,A1)
Where A1 would have the employee ID.
Check out this post I made about creating hyperlinks from External Data:
http://www.spreadsheetsmadeeasy.com/creating-hyperlinks-with-external-data/
Scroll down to the "Add Hyperlinks" section for more info.