I'm trying to make an Advanced Search now for weeks in my Userform where it will filter and display the result on the ListBox while typing a value. But somehow my ComboBox that serves as a filter has a dropdown function already.
I have no idea how can I make it like the way I wanted it.
My UserForm contains 8 columns.
Here is the existing code for the ComboBox filter
Private Sub cmbSearch_Change()
'The function of this code below is for the user to click a value from the ComboBox and then the result will be displayed on the TextBoxes and ListBox.
x = Sheets("DATA STOCK").Range("A" & Rows.Count).End(xlUp).Row
For y = 2 To x
If Sheets("DATA STOCK").Cells(y, 1).Text = cmbSearch.Value Then
cmbSchema.Text = Sheets("DATA STOCK").Cells(y, 1)
cmbEnvironment.Text = Sheets("DATA STOCK").Cells(y, 2)
cmbHost.Text = Sheets("DATA STOCK").Cells(y, 3)
cmbIP.Text = Sheets("DATA STOCK").Cells(y, 4)
cmbAccessible.Text = Sheets("DATA STOCK").Cells(y, 5)
cmbLast.Text = Sheets("DATA STOCK").Cells(y, 6)
cmbConfirmation.Text = Sheets("DATA STOCK").Cells(y, 7)
cmbProjects.Text = Sheets("DATA STOCK").Cells(y, 8)
UserForm1.listHeader.RowSource = "A" + CStr(y) + ": H" + CStr(y)
Exit For
End If
Next y
End Sub
Expected Result:
The problem is I don't know how to create that kind of search filter and if it is possible even though I already have a dropdown function in my ComboBox
Saw that you've been working for weeks on this.
I have refactored your form's code and implemented the functionality you've been looking for.
As my other answer to your other question, in my opinion it's easier to work adding and removing items to the listbox, rather than working with excel ranges. (How to fix this bug in my code that doesn't allow me to update other columns in excel userform?)
Important remarks: - I've converted the data inside the sheet to an Excel Structured Table (Ctrl + T) - I took one of your previous files, so the information you have inside the table may be out of date - Testing I also modified some of the data - I suggest you copy and paste your most recent data and replace it inside the table
Here you can download the file based on your data: https://github.com/rdiazjimenez/excel-vba-userform-basic-listbox-demo/blob/master/MDM_DB_Checking_09122018_RD.xlsm
I covered basic operations (Create, Read, Update, Delete and Search/Filter) with Excel Data loaded into a Listbox inside a Userform.
This is the code behind the form:
Option Explicit
' Code updated
Private Sub btnDelete_Click()
Application.EnableEvents = False
Call mCode.Delete
Application.EnableEvents = True
End Sub
' Code updated
Private Sub btnView_Click()
Application.EnableEvents = False
Call mCode.Read
Application.EnableEvents = True
End Sub
' Code updated
Private Sub cmbAdd_Click()
Application.EnableEvents = False
Call mCode.Create
Application.EnableEvents = True
End Sub
' Code updated
Private Sub cmbClearFields_Click()
Application.EnableEvents = False
Call mCode.ClearControls
Application.EnableEvents = True
End Sub
' Code updated
Private Sub cmbSearch_Change()
Application.EnableEvents = False
Call FilterList(Me.listHeader, Me.cmbSearch.Text)
Application.EnableEvents = True
End Sub
' Code updated
Private Sub cmbUpdate_Click()
Application.EnableEvents = False
Call mCode.Update
Application.EnableEvents = True
End Sub
' Code updated
Private Sub CommandButton5_Click()
Application.EnableEvents = False
Call mCode.ClearList
Application.EnableEvents = True
End Sub
' Code from this event was removed
Private Sub listHeader_Click()
End Sub
' Code added
Private Sub listHeader_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Application.EnableEvents = False
Call mCode.LoadControls
Application.EnableEvents = True
End Sub
' Code partially updated
Private Sub UserForm_Initialize()
Me.cmbSearch.List = ThisWorkbook.Sheets("PRESTAGE DB").ListObjects("TableData").ListColumns(1).DataBodyRange.Value
Me.cmbEnvironment.AddItem "DEV"
Me.cmbEnvironment.AddItem "UAT"
Me.cmbEnvironment.AddItem "SIT"
Me.cmbEnvironment.AddItem "QA"
Me.cmbEnvironment.AddItem "PROD"
Me.cmbAccessible.AddItem "Y"
Me.cmbAccessible.AddItem "N"
Me.cmbIP.AddItem "1521"
Me.cmbProjects.AddItem "DP - proposed for DEV/SIT"
Me.cmbProjects.AddItem "PH EFUSE SIT"
Me.cmbProjects.AddItem "MyAXA SG DEV/DIT"
End Sub
And this is the code inside a module called mCode:
Option Explicit
' Global variables
Const sheetName As String = "PRESTAGE DB"
Const tableName As String = "TableData"
Public Sub ShowUserForm()
oUserForm.Show
End Sub
Public Sub Read()
' Comments: Loads the data from an excel table (listobject) into a listbox located inside a userform
' Params :
' Notes : Adapt the initialize variables section
' Created : 2019/01/25 RD www.ricardodiaz.co
' Modified:
' Define objects variables
Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
Dim myListObject As Excel.listObject
Dim myRange As Excel.Range
' Define other variables
Dim columnCount As Integer
Dim selectedItem As Integer
Dim rowCounter As Long
Dim columnCounter As Integer
'''''''' Initialize objects ''''''''
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Load the data from the Excel table into a range variable
' Note: It's safer to refer to thisworkbook
Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)
'''''''' Initialize variables ''''''''
myUserForm.listHeader.ColumnWidths = "130 pt;60 pt;82 pt;55 pt;70 pt;195 pt;170 pt;130 pt"
' Set the number of columns to the same of the table in the Excel sheet
columnCount = myListObject.ListColumns.Count
' Get the current selected item
selectedItem = myUserForm.listHeader.ListIndex ' this returns -1 if none is selected
' Clear the listbox contents
Call mCode.ClearList
' Set the number of columns to load into the listbox
myUserForm.listHeader.columnCount = columnCount
' Loop through each row and load it into the listbox
' Note: begins with 2 because the first row are the table headers
For rowCounter = 2 To myListObject.Range.Rows.Count
With myUserForm.listHeader
.AddItem
' Load value of each column in the table row
For columnCounter = 0 To columnCount
.List(rowCounter - 2, columnCounter) = myListObject.Range.Cells(rowCounter, columnCounter + 1).Value
Next columnCounter
End With
Next
' Select previously selected row
If selectedItem < myUserForm.listHeader.ListCount Then
myUserForm.listHeader.ListIndex = selectedItem
End If
' Clean up objects
Set myListObject = Nothing
Set myUserForm = Nothing
End Sub
Public Sub Create()
' Comments: Adds a new row with the data entered by the user and reloads the listbox inside the userform
' Params :
' Notes : Adapt the initialize variables section
' Created : 2019/01/25 RD www.ricardodiaz.co
' Modified:
' Define objects variables
Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
Dim myListObject As Excel.listObject
Dim myListRow As Excel.listRow
'''''''' Initialize objects ''''''''
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Add the information to the Excel table
Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)
' Validate if all the information is correct
If myUserForm.cmbEnvironment.Text = vbNullString _
Or myUserForm.cmbHost.Text = vbNullString _
Or myUserForm.cmbIP.Text = vbNullString _
Or myUserForm.cmbAccessible.Text = vbNullString _
Or myUserForm.cmbLast.Text = vbNullString Then
MsgBox "Some fields cannot be blank!", vbCritical, "Data Missing"
Exit Sub
End If
' Add a blank row at the end of the Excel table
Set myListRow = myListObject.ListRows.Add
' Set the information into de excel table
With myListRow
.Range(1) = myUserForm.cmbSchema.Text
.Range(2) = myUserForm.cmbEnvironment.Text
.Range(3) = myUserForm.cmbHost.Text
.Range(4) = myUserForm.cmbIP.Text
.Range(5) = myUserForm.cmbAccessible.Text
.Range(6) = myUserForm.cmbLast.Text
.Range(7) = myUserForm.cmbConfirmation.Text
.Range(8) = myUserForm.cmbProjects.Text
End With
MsgBox "Data Added!"
' Reload the data into the listbox
Call mCode.Read
' Select the last item in the listbox
myUserForm.listHeader.ListIndex = myUserForm.listHeader.ListCount - 1
' Clear control's contents
Call ClearControls ' Note that this is a private procedure inside the mCode module
' Clean up objects
Set myListRow = Nothing
Set myListObject = Nothing
Set myUserForm = Nothing
End Sub
Public Sub Update()
' Comments: Updates a row with the data entered by the user and reloads the listbox inside the userform
' Params :
' Notes : Adapt the initialize variables section
' Created : 2019/01/25 RD www.ricardodiaz.co
' Modified:
' Define objects variables
Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
Dim myListObject As Excel.listObject
Dim myListRow As Excel.listRow
' Define variables
Dim selectedItem As Integer
'''''''' Initialize objects ''''''''
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Add the information to the Excel table
Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)
' Define selected row number
selectedItem = myUserForm.listHeader.ListIndex + 1
' Exit if there are no other rows
If selectedItem = 0 Then
MsgBox "There are no rows left!"
Exit Sub
End If
' Initialize the row at the end of the Excel table
Set myListRow = myListObject.ListRows(selectedItem)
' the following section is exactly as the Create procedure, so you theorically could make just one procedure for Create and Update
' Set the information into de excel table
With myListRow
.Range(2) = myUserForm.cmbEnvironment.Text
.Range(3) = myUserForm.cmbHost.Text
.Range(4) = myUserForm.cmbIP.Text
.Range(5) = myUserForm.cmbAccessible.Text
.Range(6) = myUserForm.cmbLast.Text
.Range(7) = myUserForm.cmbConfirmation.Text
.Range(8) = myUserForm.cmbProjects.Text
End With
' Reload the data into the listbox
Call mCode.Read
' Select the updated item in the listbox
myUserForm.listHeader.ListIndex = selectedItem - 1
MsgBox "Data Updated!"
' Clear control's contents
Call ClearControls ' Note that this is a private procedure inside the mCode module
' Clean up objects
Set myListRow = Nothing
Set myListObject = Nothing
Set myUserForm = Nothing
End Sub
Public Sub Delete()
' Comments: Deletes a row with the data entered by the user and reloads the listbox inside the userform
' Params :
' Notes : Adapt the initialize variables section
' Created : 2019/01/25 RD www.ricardodiaz.co
' Modified:
' Define objects variables
Dim myUserForm As oUserForm ' Note: you're defining the variable as the class of the userform. This gives you access to the userform's controls later
Dim myListObject As Excel.listObject
Dim myListRow As Excel.listRow
' Define variables
Dim selectedItem As Integer
'''''''' Initialize objects ''''''''
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Add the information to the Excel table
Set myListObject = ThisWorkbook.Worksheets(sheetName).ListObjects(tableName)
' Define selected row number
selectedItem = myUserForm.listHeader.ListIndex + 1
' Exit if there are no other rows
If selectedItem = 0 Then
MsgBox "There are no rows left or you didn't select a valid row!"
Exit Sub
End If
If MsgBox("Are you sure you want to delete this row?", vbYesNo + vbQuestion, "Yes") = vbNo Then
Exit Sub
End If
' Initialize the row at the end of the Excel table
Set myListRow = myListObject.ListRows(selectedItem)
' Delete the row
myListRow.Delete
' Reload the data into the listbox
Call mCode.Read
' Select the next item in the listbox
myUserForm.listHeader.ListIndex = WorksheetFunction.Min(selectedItem - 1, myUserForm.listHeader.ListCount) - 1
' Clean up objects
Set myListRow = Nothing
Set myListObject = Nothing
Set myUserForm = Nothing
End Sub
Public Sub ClearList()
' Comments: Clear the listbox
' Define objects variables
Dim myUserForm As oUserForm
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
myUserForm.listHeader.Clear
End Sub
Public Sub LoadControls()
' Comments: Loads the selected row's data into the controls
' Define objects variables
Dim myUserForm As oUserForm
Dim selectedItem As Integer
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Get the row of the selected item in the listbox
selectedItem = myUserForm.listHeader.ListIndex
' Set the control's text to each column of the selected item
myUserForm.cmbSchema.Value = myUserForm.listHeader.List(selectedItem, 0)
myUserForm.cmbEnvironment.Value = myUserForm.listHeader.List(selectedItem, 1)
myUserForm.cmbHost.Value = myUserForm.listHeader.List(selectedItem, 2)
myUserForm.cmbIP.Value = myUserForm.listHeader.List(selectedItem, 3)
myUserForm.cmbAccessible.Value = myUserForm.listHeader.List(selectedItem, 4)
myUserForm.cmbLast.Value = myUserForm.listHeader.List(selectedItem, 5)
myUserForm.cmbConfirmation.Value = myUserForm.listHeader.List(selectedItem, 6)
myUserForm.cmbProjects.Value = myUserForm.listHeader.List(selectedItem, 7)
' Clean up objects
Set myUserForm = Nothing
End Sub
Public Sub ClearControls()
' Comments: Reset controls to empty strings
' Define objects variables
Dim myUserForm As oUserForm
' Init the userform
' Note: When you initialize it directly with the name of the form, you can access the controls of the userform too
Set myUserForm = oUserForm
' Clear the controls
myUserForm.cmbSchema.Text = vbNullString
myUserForm.cmbEnvironment.Text = vbNullString
myUserForm.cmbHost.Text = vbNullString
myUserForm.cmbIP.Text = vbNullString
myUserForm.cmbAccessible.Text = vbNullString
myUserForm.cmbLast.Text = vbNullString
myUserForm.cmbConfirmation.Text = vbNullString
myUserForm.cmbProjects.Text = vbNullString
' Clean up objects
Set myUserForm = Nothing
End Sub
Public Sub FilterList(oLb As MSForms.ListBox, strFiltro As String)
Dim columnCounter As Integer
Dim listString As String
Dim rowCounter As Integer
oLb.ListIndex = -1
' Read the whole list
Call mCode.Read
' Remove unmatching items
For rowCounter = oLb.ListCount - 1 To 0 Step -1
listString = vbNullString
' Concat the list columns values in one string
For columnCounter = 0 To oLb.columnCount
listString = listString & oLb.Column(columnCounter, rowCounter)
Next columnCounter
If InStr(1, listString, strFiltro, 1) = 0 Then
' Remove items that don't match
oLb.RemoveItem rowCounter
End If
Next
End Sub