3 or More Dependent Data Validation, with VBA, easy to set up

Akuini

Well-known Member
Joined
Feb 1, 2016
Messages
5,271
Office Version
  1. 365
Platform
  1. Windows
I want to share a macro to set up multi dependent data validation with vba. Some versions of dependent data validation use formulas to set them up, usually with indirect functions. For 2 or 3 dependent data validation & small data set, it's pretty easy to set it up, but for more than 3, it might be difficult to maintain as it requires lots of tables & lots of helper columns. This version uses vba, you only need 1 table, 1 helper column & 1 named range. The code is a bit complicated but easy to set up and maintain.

This is an example of 3 dependent data validation, with VBA. You can easily set up more than 3 dependent data validations as needed.
Notes:
1. You only need 1 table as data validation source, 1 helper column, 1 named range & 1 simple formula in data validation (ie =xName).
2. The columns where data validation reside may or may not be contiguous.
3. The list in the table may have duplicate, empty & unsorted, but the code will make the list in data validation unique, sorted & non-empty. The list is also dynamic, you can add more data as needed.
4. In the range with data validation, changing or deleting cell contents will delete cells in the next column with data validation.
5. But one caveat of using macro is when macro changes/writes something on sheet it will delete Undo Stack, so at that time you can't use UNDO. In this case it happens every time you put the cursor in a cell with data validation.

The File:

dhee - multiple data validation non adjacent column 2.jpg


The code:
VBA Code:
Option Explicit
'=================================================================================================
'=============== ADJUST THE CODE IN THIS PART: ===================================

'sheet's name where the list for data validation is located. [in the example: sheet "sheet2"]
Private Const sList As String = "sheet2"

'table's name where the list for data validation is located. [in the example: "Table1"]
Private Const sTable As String = "Table1"

'sDT & sDV must be in correct order (in this example 'STATE > CITY > REP).
'You can add number of columns as needed.
'Column number on the table "Table1": 'STATE > CITY > REP
Private Const sDT As String = "1,2,4"

'Column where data validation is located 'STATE > CITY > REP
Private Const sDV As String = "B:B,D:D,G:G"

'the helper column, first cell
Private Const xH As String = "H1"

'the name range as the source of data validation
Private Const xN As String = "xName"
'==================================================================================================
'==================================================================================================
Private xOld As String

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

If Target.Cells.CountLarge > 1 Then Exit Sub
    
If Not Intersect(Target, Range(sDV)) Is Nothing Then
    If isValid(Target) Then     'if activecell has data validation type 3
       If Target.Validation.Formula1 = "=" & xN Then 'its formula is "=xName"
       
       Dim d As Object, va, flag As Boolean, z, q, vb, x
       Dim i As Long, y As Long, w As Long
       
       Application.CutCopyMode = False 'prevent paste to the range with the DV
       xOld = Target.Value
       Set d = CreateObject("scripting.dictionary"):  d.CompareMode = vbTextCompare
       'columns with data validation:  sDV = "B:B,D:D,G:G"
       z = Application.Transpose(Application.Transpose(Split(sDV, ","))) ''create 1D array, variant/string type, Lbound = 1
       
       For i = 1 To UBound(z)
           If Target.Column = Range(z(i)).Column Then w = i: Exit For
       Next
  
       'reset xName to blank
'       ThisWorkbook.Names(xN).RefersTo = Sheets(sList).Range(xH)
       Sheets(sList).Range(xH).Name = xN  'blank cell

       If w > 1 Then 'if previous col with DV is empty then exit sub (with xName is blank)
           If ActiveSheet.Cells(Target.Row, z(w - 1)) = "" Then Exit Sub
       End If

          
           'Column number on the source table: sDT = "1,2,4"
            q = Evaluate("{" & sDT & "}") 'create 1D array, variant/double type, Lbound = 1
      
        'populate data from Table1,
        '"Application.Max(q)" is to limit the column range as needed for populating the list.
        va = Sheets(sList).ListObjects(sTable).DataBodyRange.Resize(, Application.Max(q)).Value
   
       For i = 1 To UBound(va, 1)
           flag = True
           
           If w = 1 Then 'if target is in first data validation column
               d(va(i, q(w))) = Empty
           Else
               'apply criteria from all previous column
               For y = 1 To w - 1
                   If UCase(va(i, q(y))) <> UCase(ActiveSheet.Cells(Target.Row, z(y))) Then flag = False: Exit For
               Next
               'if all criteria are met
               If flag = True Then d(va(i, q(w))) = Empty
           End If
       Next

            If d.Exists("") Then d.Remove ""
            If d.Count > 0 Then
                Dim c As Range
                Application.EnableEvents = False
                Application.ScreenUpdating = False
                    'populate d.keys to helper column & sort it
                    With Sheets(sList)
                        .Columns(.Range(xH).Column).ClearContents
                        Set c = .Range(xH).Resize(d.Count, 1).Offset(1)
                        c = Application.Transpose(Array(d.Keys))
                        c.Sort Key1:=c.Cells(1), Order1:=xlAscending, Header:=xlNo
                    End With
                   'populating range to xName
                    c.Name = xN
        
                Application.ScreenUpdating = True
                Application.EnableEvents = True
            End If
        End If
    End If
End If

End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
    
If Not Intersect(Target, Range(sDV)) Is Nothing Then
    
    If isValid(Target) Then     'if activecell has data validation type 3
       If Target.Validation.Formula1 = "=" & xN Then 'if its formula is "=xName"
            If xOld <> Target.Value Then
            
                Dim i As Long, w As Long, z
            
                Application.EnableEvents = False
                'columns with data validation:  "B:B,D:D,G:G"
                z = Application.Transpose(Application.Transpose(Split(sDV, ",")))
                
                For i = 1 To UBound(z)
                    If Target.Column = Range(z(i)).Column Then w = i: Exit For
                Next
                     
                    'if it's not the last column with DV then clear all next column with DV
                    If w < UBound(z) Then
                        For i = w + 1 To UBound(z)
                            ActiveSheet.Cells(Target.Row, Range(z(i)).Column) = ""
                        Next
                    End If
                Application.EnableEvents = True
            End If
        End If
    End If
End If
    
End Sub

Sub toEnableEvent()
Application.EnableEvents = True
End Sub

Function isValid(f As Range) As Boolean
    Dim v
    On Error Resume Next
        v = f.Validation.Type
    On Error GoTo 0
    isValid = v = 3
End Function
 
@Akuini , I would like to add a 4th dependent drop-down (e.g., Contract #). I tried modifying the formulas but I cannot get it to recognize the new column in Table1.
 
Upvote 0

Excel Facts

When did Power Query debut in Excel?
Although it was an add-in in Excel 2010 & Excel 2013, Power Query became a part of Excel in 2016, in Data, Get & Transform Data.
I would like to add a 4th dependent drop-down (e.g., Contract #). I tried modifying the formulas but I cannot get it to recognize the new column in Table1.
Formula in which post are you referring to?
 
Upvote 0
The one that was posted on Oct 26, 2021..."I want to share a macro to set up multi dependent data validation with vba..."
Could you upload a sample workbook (without sensitive data) to a sharing site like dropbox.com or google drive?
And then share the link here.
It's easier if I have a sample workbook to test.
 
Upvote 0
I want to share a macro to set up multi dependent data validation with vba. Some versions of dependent data validation use formulas to set them up, usually with indirect functions. For 2 or 3 dependent data validation & small data set, it's pretty easy to set it up, but for more than 3, it might be difficult to maintain as it requires lots of tables & lots of helper columns. This version uses vba, you only need 1 table, 1 helper column & 1 named range. The code is a bit complicated but easy to set up and maintain.

This is an example of 3 dependent data validation, with VBA. You can easily set up more than 3 dependent data validations as needed.
Notes:
1. You only need 1 table as data validation source, 1 helper column, 1 named range & 1 simple formula in data validation (ie =xName).
2. The columns where data validation reside may or may not be contiguous.
3. The list in the table may have duplicate, empty & unsorted, but the code will make the list in data validation unique, sorted & non-empty. The list is also dynamic, you can add more data as needed.
4. In the range with data validation, changing or deleting cell contents will delete cells in the next column with data validation.
5. But one caveat of using macro is when macro changes/writes something on sheet it will delete Undo Stack, so at that time you can't use UNDO. In this case it happens every time you put the cursor in a cell with data validation.

The File:

View attachment 49864

The code:
VBA Code:
Option Explicit
'=================================================================================================
'=============== ADJUST THE CODE IN THIS PART: ===================================

'sheet's name where the list for data validation is located. [in the example: sheet "sheet2"]
Private Const sList As String = "sheet2"

'table's name where the list for data validation is located. [in the example: "Table1"]
Private Const sTable As String = "Table1"

'sDT & sDV must be in correct order (in this example 'STATE > CITY > REP).
'You can add number of columns as needed.
'Column number on the table "Table1": 'STATE > CITY > REP
Private Const sDT As String = "1,2,4"

'Column where data validation is located 'STATE > CITY > REP
Private Const sDV As String = "B:B,D:D,G:G"

'the helper column, first cell
Private Const xH As String = "H1"

'the name range as the source of data validation
Private Const xN As String = "xName"
'==================================================================================================
'==================================================================================================
Private xOld As String

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

If Target.Cells.CountLarge > 1 Then Exit Sub
   
If Not Intersect(Target, Range(sDV)) Is Nothing Then
    If isValid(Target) Then     'if activecell has data validation type 3
       If Target.Validation.Formula1 = "=" & xN Then 'its formula is "=xName"
      
       Dim d As Object, va, flag As Boolean, z, q, vb, x
       Dim i As Long, y As Long, w As Long
      
       Application.CutCopyMode = False 'prevent paste to the range with the DV
       xOld = Target.Value
       Set d = CreateObject("scripting.dictionary"):  d.CompareMode = vbTextCompare
       'columns with data validation:  sDV = "B:B,D:D,G:G"
       z = Application.Transpose(Application.Transpose(Split(sDV, ","))) ''create 1D array, variant/string type, Lbound = 1
      
       For i = 1 To UBound(z)
           If Target.Column = Range(z(i)).Column Then w = i: Exit For
       Next
 
       'reset xName to blank
'       ThisWorkbook.Names(xN).RefersTo = Sheets(sList).Range(xH)
       Sheets(sList).Range(xH).Name = xN  'blank cell

       If w > 1 Then 'if previous col with DV is empty then exit sub (with xName is blank)
           If ActiveSheet.Cells(Target.Row, z(w - 1)) = "" Then Exit Sub
       End If

         
           'Column number on the source table: sDT = "1,2,4"
            q = Evaluate("{" & sDT & "}") 'create 1D array, variant/double type, Lbound = 1
     
        'populate data from Table1,
        '"Application.Max(q)" is to limit the column range as needed for populating the list.
        va = Sheets(sList).ListObjects(sTable).DataBodyRange.Resize(, Application.Max(q)).Value
  
       For i = 1 To UBound(va, 1)
           flag = True
          
           If w = 1 Then 'if target is in first data validation column
               d(va(i, q(w))) = Empty
           Else
               'apply criteria from all previous column
               For y = 1 To w - 1
                   If UCase(va(i, q(y))) <> UCase(ActiveSheet.Cells(Target.Row, z(y))) Then flag = False: Exit For
               Next
               'if all criteria are met
               If flag = True Then d(va(i, q(w))) = Empty
           End If
       Next

            If d.Exists("") Then d.Remove ""
            If d.Count > 0 Then
                Dim c As Range
                Application.EnableEvents = False
                Application.ScreenUpdating = False
                    'populate d.keys to helper column & sort it
                    With Sheets(sList)
                        .Columns(.Range(xH).Column).ClearContents
                        Set c = .Range(xH).Resize(d.Count, 1).Offset(1)
                        c = Application.Transpose(Array(d.Keys))
                        c.Sort Key1:=c.Cells(1), Order1:=xlAscending, Header:=xlNo
                    End With
                   'populating range to xName
                    c.Name = xN
       
                Application.ScreenUpdating = True
                Application.EnableEvents = True
            End If
        End If
    End If
End If

End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
   
If Not Intersect(Target, Range(sDV)) Is Nothing Then
   
    If isValid(Target) Then     'if activecell has data validation type 3
       If Target.Validation.Formula1 = "=" & xN Then 'if its formula is "=xName"
            If xOld <> Target.Value Then
           
                Dim i As Long, w As Long, z
           
                Application.EnableEvents = False
                'columns with data validation:  "B:B,D:D,G:G"
                z = Application.Transpose(Application.Transpose(Split(sDV, ",")))
               
                For i = 1 To UBound(z)
                    If Target.Column = Range(z(i)).Column Then w = i: Exit For
                Next
                    
                    'if it's not the last column with DV then clear all next column with DV
                    If w < UBound(z) Then
                        For i = w + 1 To UBound(z)
                            ActiveSheet.Cells(Target.Row, Range(z(i)).Column) = ""
                        Next
                    End If
                Application.EnableEvents = True
            End If
        End If
    End If
End If
   
End Sub

Sub toEnableEvent()
Application.EnableEvents = True
End Sub

Function isValid(f As Range) As Boolean
    Dim v
    On Error Resume Next
        v = f.Validation.Type
    On Error GoTo 0
    isValid = v = 3
End Function
This was so very helpful! Thank you so much for sharing. Does the helper column need to be on the same sheet? Can I put it on its own sheet and if so how do I reference it in your code?
 
Upvote 0
Hi, @xlsBruh, welcome to MrExcel.
This has nothing to do with your question:
If you're using Excel 365 you may try using the formula method instead of vba to set up multiple dependent data validation.
Please check post #30.

To answer your question:
This was so very helpful! Thank you so much for sharing. Does the helper column need to be on the same sheet? Can I put it on its own sheet and if so how do I reference it in your code?
In the example, the setup is like this:
Sheet1 : where data validation is located
Sheet2 : where the list & helper column are located
You mean you want to place the helper column in another sheet, separate from the list? say sheet3?
 
Upvote 0
Hi, @xlsBruh, welcome to MrExcel.
This has nothing to do with your question:
If you're using Excel 365 you may try using the formula method instead of vba to set up multiple dependent data validation.
Please check post #30.

To answer your question:

In the example, the setup is like this:
Sheet1 : where data validation is located
Sheet2 : where the list & helper column are located
You mean you want to place the helper column in another sheet, separate from the list? say sheet3?
That is correct. I would like the helper column on a third sheet and thank you for your response. I will also check out post #30.
 
Upvote 0
That is correct. I would like the helper column on a third sheet and thank you for your response. I will also check out post #30.
To place the helper column on sheet3:
in "Private Sub Worksheet_SelectionChange" just change the sheet name in this part:
change this:

Rich (BB code):
                    'populate d.keys to helper column & sort it
                    With Sheets(sList)
                        .Columns(.Range(xH).Column).ClearContents


to this:
Rich (BB code):
                    'populate d.keys to helper column & sort it
                    With Sheets("Sheet3")
                        .Columns(.Range(xH).Column).ClearContents

to change the column of the helper column, just amend this part (at the top of the code module):
VBA Code:
'the helper column, first cell
Private Const xH As String = "H1"
 
Upvote 0
Hi Akuini
how change table to normal range ? I want doing in my project with normal range .
my data in sheet1 is A1: E
so the combobox1 should link with column B2:B and combobox2 with column C2:C , and combobox3 with column D2:D .
thanks
 
Upvote 0
Hi Akuini
how change table to normal range ? I want doing in my project with normal range .
my data in sheet1 is A1: E
so the combobox1 should link with column B2:B and combobox2 with column C2:C , and combobox3 with column D2:D .
thanks
It's data validation not combobox.
Are talking about the code in post 1?
 
Upvote 0

Forum statistics

Threads
1,223,882
Messages
6,175,165
Members
452,615
Latest member
bogeys2birdies

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top