Excel VBA drop down list and vlookup issue - vba

I am trying to make a VBA code that will create a drop down list or have a Vlookup function in a cell.
I am new to VBA so please have mercy. :)
The problem is that with the code below it always crashes Excel.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Lookup_Range As Range
Set shList = ThisWorkbook.Sheets("ListaEchipamente")
Set Lookup_Range = shList.Range("G10", "M345")
If Cells(Target.Row, 13).Value = " " Then
With Range("J2:J100").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:="=ListaEchipamente!K10:K345"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
ElseIf Not Cells(Target.Row, 13).Value = " " Then
Cells(Target.Row, 10).Value = "=VLookup(Range(target.row, 13), Lookup_Range, 2, False)"
End If
End Sub
Thank you for the help.

Your code changing Cells(Target.Row, 10).Value triggers another Change event and you get endless loop. To avoid it disable events first:
Application.EnableEvents = False
'code to modify cells here
Application.EnableEvents = True

Related

VBA - Change Formula dynamically

I have an drop-down validating formuala for a cell and am using the generic formula inside the validation in vba.
Now, I want to automate it using the formula1 part inside the with loop here.
Here goes the Code,
Lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
Lastrow2 = Sheets("Config").Cells(Rows.Count, "R").End(xlUp).Row
For i = 2 To Lastrow
With Range("M" & i).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:="=Config!R2:R10"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Next
how would you replace the part in the code - Formula1:="=Config!R2:R10" with the 10 being Lastrow2.
Thanks
The solution :
Formula1:="=Config!R2:R"&Lastrow2

VBA Code for drop-down list with dynamic range

I am trying to write a macro for multiple drop-downs in "n" cells (let's say 100) in a column. The ranges(drop-down values) for these drop-downs have to be picked from a table with same number of rows (100 in our case).
I am unable to run the for loop for the formula part (highlighted below). I want the macro to pick D2:H2 range for i=2, D3:H3 for i=3, and so on. How do I do it? Is there any alternative to this?
Looking forward to valuable inputs.
Thanks!!
Sub S_Dropdown3()
Dim wks As Worksheet: Set wks = Sheets("Sheet1")
wks.Select
Dim i As Integer
For i = 2 To 101
With Range("B" & i).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, **Formula1:="=Sheet2!D2:H2"**
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Next i
End Sub
The following code should work:
Option Explicit
Sub S_Dropdown3()
Dim wks As Worksheet
Dim i As Integer
Set wks = ThisWorkbook.Worksheets("Sheet1")
wks.Activate
For i = 2 To 101
With wks.Range("B" & i).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=Sheet2!D" & i & ":H" & i
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Next i
End Sub
Implemented changes:
Code formatting / indentation
Implementing full qualification to ensure that Sheet1 refers to Sheet1 in the workbook from which the macro is run (in case that more than one Excel file is open).
Sheets cannot be .Selected only ranges get selected. Sheets can only be .Activated. Earlier versions of Excel don't mind. Never versions of Excel will throw an error with that line.
Fully qualifying .Range("B" & i).
Finally, making the formula modular as requested in the initial post.

Create a dropdown list when a row is added using VBA

I want to write a macro that does as follows:
If you enter a value under column A, it gives a dropdown list in the same row under column B.
I have written a peice which works for the first time. But the problem is when I run it, if there is already a dropdown list in some cells, it breaks!
Sub Macro2()
Dim cell As Range
'If a value is listed
For Each cell In ActiveSheet.Range("A2:A1000")
If cell.Value <> "" Then
cell.Offset(0, 1).Select
If Selection = Empty Then
With Selection.Validation
'add list box
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=Sheet1!A2:A20"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
Next cell
End Sub
I should add that I cannot delete the content in column B, because I do not want to lose the work already there.
Here's a solution that will just delete a validation, then add back. Also, I removed the use of .Select, which can cause errors.
Dim isValid As Boolean
Sub Macro2()
Dim cell As Range
'If a value is listed
For Each cell In ActiveSheet.Range("A2:A1000")
If cell.Value <> "" Then
testIfValidation cell.Offset(0, 1)
If IsEmpty(cell.Offset(0, 1)) And Not isValid Then
With cell.Offset(0, 1).Validation
'add list box
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=Sheet1!A2:A20"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
Next cell
End Sub
Private Sub testIfValidation(ByVal cel As Range)
Dim X As Variant
On Error Resume Next
X = cel.Validation.Type
On Error GoTo 0
If IsEmpty(X) Then
Debug.Print cel.Address & " has no validation"
isValid = False
Else
isValid = True
End If
End Sub
I updated this with a test to see if a cell has validation. If it does, it'll skip it. Otherwise, proceed as usual.
Why don't you clear existing data validation before adding the new one?
Along these lines:
With Selection.Validation
' delete existing
.Delete
'add list box
.Add Type etc.
The Validation.Delete does the same thing as clicking "Clear All" in the data validation dialog. No cell content gets changed or removed.

VBA controlling user focus during iteration

quick question that shouldn't really require any of my code. During my application, I use a 'for each' loop, that loops through a range of cells, and right now when the user runs it, the focus of the screen follows the selection as it jumps from cell to cell within that range. Is there any way to prevent the focus from following the path of the loop during the iteration, maybe have the user simply see something that says "processing" until it is complete?
Thanks in advance, I appreciate any and all help.
Code:
Dim iLoop As Integer
For iLoop = 5 To lastRow
Sheets("Planners").Activate
Range("J" & iLoop).Select
Range(Cells(iLoop, 9)).Select
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="Yellow, Orange, Green, Red"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = "Invalid Entry"
.ErrorMessage = "Please choose from dropdown"
.ShowInput = True
.ShowError = True
End With
Next iLoop
Apparently you are using .Select in your code. There is a chance it's a right thing to do, but most of the time it isn't.
So stop using Select and ActiveCell and refer to cells using indices/references.
The above would be the correct solution.
The wrong solution would be to use Application.ScreenUpdating = False before the loop and Application.ScreenUpdating = True after the loop.
Edit:
Dim iLoop As long
dim w as worksheet
set w = Worksheets("Planners")
For iLoop = 5 To lastRow
With w.cells(iLoop, 9).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="Yellow, Orange, Green, Red"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = "Invalid Entry"
.ErrorMessage = "Please choose from dropdown"
.ShowInput = True
.ShowError = True
End With
Next
But given this code, you don't need a loop at all:
dim w as worksheet
set w = Worksheets("Planners")
With w.Range(w.cells(5, 9), w.cells(lastRow, 9)).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="Yellow, Orange, Green, Red"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = "Invalid Entry"
.ErrorMessage = "Please choose from dropdown"
.ShowInput = True
.ShowError = True
End With
All you need to do is add application.screenupdating = false at the start of you code (after the sub definition of course) and application.screenupdating = true at the end before 'end sub'.
It's good practice to add this to all your sub and functions as it will make them run faster as well.

VBA: jumping out of a for loop

How do I achieve the following?
Sub Macro1()
'
' Macro1 Macro
'
'
Worksheets("Drop-down").Select
n = Cells(1, 1).End(xlDown).Row
For i = 1 To n
ActiveSheet.Cells(i, 2).Select
*******************************************************
If Worksheets("Misc").Cells(2, i).Value = "" Then
continue i
End If
*******************************************************
If Worksheets("Misc").Cells(3, i).Value <> "" Then
Set validationRange = Range(Worksheets("Misc").Cells(2, i), Worksheets("Misc").Cells(2, i).End(xlDown))
Else
Set validationRange = Worksheets("Misc").Cells(2, i)
End If
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=validationRange.Address
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Next i
End Sub
Isn't this a simple flow control case? I don't understand the need for special keywords to solve it:
For i = 0 To 10
If Not condition Then
some other code
Next
EDIT: Or, in your code:
Sub Macro1()
'
' Macro1 Macro
'
'
Worksheets("Drop-down").Select
n = Cells(1, 1).End(xlDown).Row
For i = 1 To n
ActiveSheet.Cells(i, 2).Select
*******************************************************
If Not Worksheets("Misc").Cells(2, i).Value = "" Then
*******************************************************
If Worksheets("Misc").Cells(3, i).Value <> "" Then
Set validationRange = Range(Worksheets("Misc").Cells(2, i), Worksheets("Misc").Cells(2, i).End(xlDown))
Else
Set validationRange = Worksheets("Misc").Cells(2, i)
End If
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=validationRange.Address
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
********
End If
********
Next
End Sub
And to answer the other half of the question:
For n = 1 To something
If condition Then
Exit For
End If
' more code
Next n
Aren't vb's keywords capitalized?
For n = 1 To something
If condition Then
Continue For
End If
' more code
Next n
The Continue keyword does what you want.
http://msdn.microsoft.com/en-us/library/801hyx6f(VS.80).aspx
It's a too old question, but just for sake of correctness and completeness in this page, this is one of the situations that Goto can be used without resulting in Spaghetti code...
It leverages VBA's Loop to almost any other newer programming language, and provides VBA programmers with the same functionality described by Eric in another answer - but Eric's answer does not works in VBA:
For n = 1 To something
If needToExitLoopEntirely Then Exit For
If condition Then GoTo ContinueFor
' more code
' ...
' more code
ContinueFor: '<=this is a label;
Next n