VBA Userform data change check - excel

I am using a userform to update data in a worksheet, I have an update command button to copy the data from the 'data' worksheet to the 'archive' and replace in the 'data' worksheet (essentially the 'archive' is a log of all previous lines and the 'data' is the most recent information)
The information is changed in text boxes and combo boxes
What Im struggling with is for the 'update' cmdbutton to first check if any changes where made before copying the data, if not I want a msg box to read 'no change in data, please close form'
Here is the code for the userform so far:
Private Sub cmdUpdate_Click()
' To write edited info of userform2 to Sheets("Data")
Dim LastRow As Long
Dim ABnum As Double
Dim ABrng As Range
Dim WriteRow As Long
'error statement
On Error GoTo errHandler:
'hold in memory and stop screen flicker
Application.ScreenUpdating = False
' Make sure we're on the right sheet
With Sheets("Data")
' Get the last row used so can set up the search range
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
' Set the range to search for the AB number
Set ABrng = .Range("A1:A" & LastRow)
' Get the AB number from what is selected on userform2
ABnum = txtup1.Value
' Get the row of sheet for this AB number
WriteRow = Application.Match(ABnum, ABrng, 0)
' Make this AB number the active cell
With .Cells(WriteRow, 1)
' Write in all the editable options
Sheets("Archive").Range("A" & Rows.Count).End(xlUp)(2).Resize(, 14).Value = .Resize(, 14).Value
.Offset(0, 4) = cboup3.Value
.Offset(0, 5) = cboup4.Value
.Offset(0, 6) = cboup5.Value
.Offset(0, 7) = cboup6.Value
.Offset(0, 8) = Date
.Offset(0, 9) = txtrev.Value
.Offset(0, 12) = txtup9.Value
.Offset(0, 13) = txtup8.Value
End With
End With
' Filter the Data
FilterMe
' Close the form
Unload Me
MsgBox ("Enquiry E0" + Me.txtup1.Text + " has been updated")
errHandler:
'Protect all sheets if error occurs
'Protect_All
'show error information in a messagebox
If Err.Number <> 0 Then
MsgBox "Error " & Err.Number & " just occured."
End If
End Sub

The easiest way would be to write a function to compare the values.
Private Sub cmdUpdate_Click()
' To write edited info of userform2 to Sheets("Data")
Dim LastRow As Long
Dim ABnum As Double
Dim ABrng As Range
Dim WriteRow As Long
'error statement
On Error GoTo errHandler:
'hold in memory and stop screen flicker
Application.ScreenUpdating = False
' Make sure we're on the right sheet
With Sheets("Data")
' Get the last row used so can set up the search range
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
' Set the range to search for the AB number
Set ABrng = .Range("A1:A" & LastRow)
' Get the AB number from what is selected on userform2
ABnum = txtenqup.Value
' Get the row of sheet for this AB number
WriteRow = Application.Match(ABnum, ABrng, 0)
' Make this AB number the active cell
With .Cells(WriteRow, 1)
'Check for changes
If Not hasValuePairsChanges(.Offset(0, 4).Value, cboup3.Value, _
.Offset(0, 5).Value, cboup4.Value, _
.Offset(0, 6).Value, cboup5.Value, _
.Offset(0, 7).Value, cboup6.Value, _
CDate(.Offset(0, 8).Value), Date, _
CDbl(.Offset(0, 9).Value), CDbl(txtrev.Value), _
.Offset(0, 12).Value, txtnotes.Value, _
.Offset(0, 13).Value, txtdtime.Value) Then
MsgBox "No Change in Data", vbInformation, ""
Exit Sub
End If
' Write in all the editable options
Sheets("Archive").Range("A" & Rows.Count).End(xlUp)(2).Resize(, 14).Value = .Resize(, 14).Value
.Offset(0, 4) = cboup3.Value
.Offset(0, 5) = cboup4.Value
.Offset(0, 6) = cboup5.Value
.Offset(0, 7) = cboup6.Value
.Offset(0, 8) = Date
.Offset(0, 9) = txtrev.Value
.Offset(0, 12) = txtnotes.Value
.Offset(0, 13) = txtdtime.Value
End With
End With
' Filter the Data
FilterMe
' Close the form
Unload Me
MsgBox ("Enquiry E0" + Me.txtenqup.Text + " has been updated")
errHandler:
'Protect all sheets if error occurs
'Protect_All
'show error information in a messagebox
If Err.Number <> 0 Then
MsgBox "Error " & Err.Number & " just occured."
End If
End Sub
Function hasValuePairsChanges(ParamArray Args() As Variant) As Boolean
Dim n As Long
For n = 0 To UBound(Args) Step 2
If Not Args(n) = Args(n + 1) Then
hasValuePairsChanges = True
Exit Function
End If
Next
End Function

Related

Excel 2016, VBA, Run-time error 13: type mismatch error

I have created a UserForm with some textboxes and comboboxes inside, the data that is typed in textboxes are supposed to be inserted in cell in the sheet, the determation of which cell is based on the value in ComboBox4. unfortunately the code keeps giving me error: "Run-time error '13': Type mismatch" and I have not been able to find out what is going wrong?
if someone knows what the problem is please let me know.
Private Sub UserForm_Initialize()
ComboBox3.List = [ADMIN!e2:E1000].Value
ComboBox4.List = [PRODUCTION!O6:O1000].Value
End Sub
Private Sub ACCEPTBUTTON_Click()
Application.ScreenUpdating = False
Worksheets("PRODUCTION").Activate
Dim C As Long
For C = 1000 To 1 Step -1
If Cells(C + 1, 1) Like ComboBox4 Then
Cells(C + 1, 1).EntireRow.Select
Selection.EntireRow.Hidden = False
Application.CutCopyMode = False
End If
Next C
Range("AC" & (ActiveCell.Row)).Value = TextBox1.Value
Range("AD" & (ActiveCell.Row)).Value = TextBox2.Value
Range("AE" & (ActiveCell.Row)).Value = TextBox3.Value
Range("AF" & (ActiveCell.Row)).Value = TextBox4.Value
Range("AG" & (ActiveCell.Row)).Value = TextBox5.Value
Range("AH" & (ActiveCell.Row)).Value = TextBox6.Value
Range("AI" & (ActiveCell.Row)).Value = TextBox7.Value
Range("AJ" & (ActiveCell.Row)).Value = TextBox8.Value
ActiveCell.EntireRow.RowHeight = 16
Unload Me
Application.ScreenUpdating = True
End Sub
Here's some commented code that should work for you. I did find it strange that you populate the values in ComboBox4 from column O, but then search column A for matches, is that intentional? (In the provided code, it searches for matches from the same list as populated the combobox which will guarantee a match is found).
Also, instead of a 1000 long loop to find the matches, this uses a Range.Find loop to increase speed and efficiency.
'Declare userform variables that any of this userform's Subs can reference
Private wb As Workbook
Private wsAdm As Worksheet
Private wsPrd As Worksheet
Private rAdmList As Range
Private rPrdList As Range
Private Sub UserForm_Initialize()
'Populate userform variables
Set wb = ThisWorkbook
Set wsAdm = wb.Worksheets("ADMIN")
Set wsPrd = wb.Worksheets("PRODUCTION")
Set rAdmList = wsAdm.Range("E2", wsAdm.Cells(wsAdm.Rows.Count, "E").End(xlUp)) 'Dynamically size list
Set rPrdList = wsPrd.Range("O6", wsPrd.Cells(wsPrd.Rows.Count, "O").End(xlUp)) 'Dynamically size list
Me.ComboBox3.List = rAdmList.Value
Me.ComboBox4.List = rPrdList.Value
End Sub
Private Sub ACCEPTBUTTON_Click()
'Check if anything is selected from ComboBox4
If Me.ComboBox4.ListIndex = -1 Then
Me.ComboBox4.SetFocus
MsgBox "Must select a Production item"
Exit Sub
End If
'An item from the production list in combobox4 has been confirmed to be selected
'Search the corresonding ComboBox4 list range to find the corresponding row
'(In your original code, you are searching column A instead of the column that populated the combobox which is column O, is there a reason for that?)
Dim rFound As Range, sFirst As String
Set rFound = rPrdList.Find(Me.ComboBox4.Text, rPrdList(rPrdList.Cells.Count), xlValues, xlWhole)
If Not rFound Is Nothing Then
sFirst = rFound.Address 'Record first address of found item
Do
'Matching row found, unhide and populate cells with textbox values
'Note that there is currently no check or validation that the textboxes are populated
rFound.EntireRow.Hidden = False
wsPrd.Cells(rFound.Row, "AC").Value = Me.TextBox1.Text
wsPrd.Cells(rFound.Row, "AD").Value = Me.TextBox2.Text
wsPrd.Cells(rFound.Row, "AE").Value = Me.TextBox3.Text
wsPrd.Cells(rFound.Row, "AF").Value = Me.TextBox4.Text
wsPrd.Cells(rFound.Row, "AG").Value = Me.TextBox5.Text
wsPrd.Cells(rFound.Row, "AH").Value = Me.TextBox6.Text
wsPrd.Cells(rFound.Row, "AI").Value = Me.TextBox7.Text
wsPrd.Cells(rFound.Row, "AJ").Value = Me.TextBox8.Text
'Search for next cell that matches
Set rFound = rPrdList.FindNext(rFound)
Loop While rFound.Address <> sFirst 'Loop until back at first address
Else
'If the item wasn't found, it's because the user manually typed in something in the combobox, or other error occurred
Me.ComboBox4.SetFocus
MsgBox "Invalid value entered for Production item"
Exit Sub
End If
Unload Me
End Sub

populate worksheet from excel table

I have been asked to remake the excel workbook to index where we keep the items.
I have an excel sheet with a table ( excel table) that contains the information.
If the there the value in column 6 ="10" then that means the item is in box 10.
then I need to get the right shelve, this is found by the numbers in column 7 (shelve) and 8 (rack). subsequently the information about the item has to be put in another sheet which gives a visual representation of the box.
I am struggling to get the desired result, does anyone have some suggestions?
Sub box()
Dim rng As Range
For x = 1 To 12
Set rng = Sheets("Register").ListObject("Table1").Range(x, 8).Value
If Range("Table1").ListObject.Range(x, 6).Value = "10" Then
If Range("Table1").ListObject.Range(x, 7).Value = "1" Then
Sheets("box 10").Range(3, rng).Value = Range("Table1").ListObject.Range(x, 2).Value & Range("Table1").ListObject.Range(x, 3)
End If
End If
Next x
End Sub
Please, try the next code. It will iterate in the table DataBodyRange and build a sheet name obtained by concatenation of "Box " with value in table column 6 (in your workbook). If such a sheet does not exist, a warning message is sent and stops the code:
Option Explicit
Sub box()
Dim boxVal As String, tbl As ListObject, shBox As Worksheet, rngRef As Range, x As Long
Dim shelvNo As Long, rackNo As Long
Dim iRow As Long: iRow = 1 ' row where "rack" exist
Dim iCol As Long: iCol = 1 'column letter where "rack" exists (C:C)
Set tbl = Sheets("Register").ListObjects("Table1")
For x = 1 To tbl.DataBodyRange.Rows.Count 'on the frist row there are ABC, ABC etc.
If tbl.DataBodyRange.Cells(x, 1) = "" Then Exit For
boxVal = tbl.DataBodyRange.Cells(x, 6).Value
On Error Resume Next
Set shBox = Sheets("Box " & boxVal) 'set the sheet of the appropriate box 'set the sheet of the appropriate box
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
MsgBox "No sheet named """ & "box " & tbl.DataBodyRange.Cells(x, 6).Value & """ exists" & vbCrLf & _
"Please, create it and run the code again!": Exit Sub
End If
On Error GoTo 0
Set rngRef = shBox.Cells(iRow, iCol)
shelvNo = iRow + 1 + tbl.DataBodyRange.Cells(x, 7).Value
rackNo = iCol + tbl.DataBodyRange.Cells(x, 8).Value - 1
rngRef.Offset(shelvNo, rackNo).Value = tbl.DataBodyRange.Cells(x, 2).Value & " " & tbl.DataBodyRange.Cells(x, 3).Value
Next x
MsgBox "Ready..."
End Sub

adding data from userform into table

I created a userform to add data in excel.
The data is been added quite good but the problem is that they are added first in total row then outside the table I have created
here is the code I am using:
Sub Submit_Data()
Dim iRow As Long
If adminpanel.txtRowNumber.Value = "" Then
iRow = student.Range("A" & Rows.Count).End(xlUp).Row + 1
Else
iRow = adminpanel.txtRowNumber.Value
End If
With student.Range("A" & iRow)
.Offset(0, 0).Value = "=Row()-1"
.Offset(0, 1).Value = adminpanel.Studentname.Value
.Offset(0, 2).Value = adminpanel.Class.Value
.Offset(0, 3).Value = adminpanel.School.Value
.Offset(0, 4).Value = adminpanel.Mobile.Value
.Offset(0, 5).Value = adminpanel.Email.Value
.Offset(0, 6).Value = adminpanel.txtImagePath.Value
End With
Call Reset_Form
Application.ScreenUpdating = True
MsgBox "data are done"
End Sub
If you're working with a Table/ListObject then it has a ListRows.Add method which you should use when you need to add a new row. From that row you can get its Range property.
Sub Submit_Data()
Dim iRow As Long, tblRow As Range, lo As ListObject
Set lo = student.ListObjects(1) 'get a reference to your table
If Len(adminpanel.txtRowNumber.Value) = 0 Then
Set tblRow = lo.ListRows.Add.Range '<< add a new row and get its range
Else
'get a reference to the existing row
iRow = CLng(adminpanel.txtRowNumber.Value)
Set tblRow = Application.Intersect(student.Rows(iRow), _
lo.DataBodyRange)
End If
'Fill the row in one operation using an array
tblRow.Value = Array(tblRow.Row - 1, adminpanel.Studentname.Value, _
adminpanel.Class.Value, adminpanel.School.Value, _
adminpanel.Mobile.Value, adminpanel.Email.Value, _
adminpanel.txtImagePath.Value)
Reset_Form
MsgBox "data are done"
End Sub

VBA Userform Listbox Conditional Logic Not Working as Intended

I have a Userform with a listbox for which I am using conditional logic to determine output values to the sheet of selected or non-selected items in the listbox. The issue is that when the Textbox (Tbl_AliasName) is blank, the code executes this:
ElseIf .Selected(k) = True And Tbl_AliasName = vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Trim(Cells(2, 1).Value2) & "." & .Column(1, k)
But if Tbl_AliasName is not blank then the code does nothing, but it is supposed to do this:
ElseIf .Selected(k) = True And Tbl_AliasName <> vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Tbl_AliasName & "." & .Column(1, k)
I have used several variations of If statements, and non of which have worked.
Below is My Code:
Option Explicit
Public Tbl_AliasName As String
Tbl_AliasName = Trim(UserForm_Finder.txtConcat.Value)
Private Sub BtnConcat_Click()
Dim k As Long, lstbxRow As Long, LR As Long
lstbxRow = 1
'****************
'This if statement works perfectly
If (Cells(2, 1).Value2 = vbNullString Or Cells(2, 2).Value2 = vbNullString) _
And Tbl_AliasName = vbNullString Then
MsgBox "You must Search for a Table or Column first.", _
vbExclamation, "Error Encountered"
Exit Sub
ElseIf (UserForm_Finder.ListBx_TblsCols.ListCount = 0 And Tbl_AliasName <> vbNullString) Then
MsgBox "You must Search for a Table or Column first.", _
vbExclamation, "Error Encountered"
'(Cells(2, 1).Value2 = vbNullString Or Cells(2, 2).Value2 = vbNullString) And _
Exit Sub
End If
With UserForm_Finder.ListBx_TblsCols
For k = 0 To .ListCount - 1
'****************
This is where the problems begin
If .Selected(k) = False Then
MsgBox "You must Select 1 or more items from the list box.", _
vbExclamation, "Error Encountered"
Exit Sub
ElseIf .Selected(k) = True And Tbl_AliasName <> vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Tbl_AliasName & "." & .Column(1, k)
ElseIf .Selected(k) = True And Tbl_AliasName = vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Trim(Cells(2, 1).Value2) & "." & .Column(1, k)
End If
Next k
End With
End Sub
My goal is to do the following:
If a Textbox (Tbl_AliasName) is not blank and the user has selected one or more items in the listbox (ListBx_TbleCols) then concatenate the Tbl_AliasName to the selected items in the listbox
If Tbl_AliasName is blank, then use the value in Cells(2,1) to concatenate to the selected Items in the list box.
I have tried the following additions:
Dim LstBxItemSelected As Boolean
'This was placed in the for loop
LstBxItemSelected = True
'this was placed outside the for loop
If LstBxItemSelected = False Then
MsgBox "You must Select 1 or more items from the list box.", _
vbExclamation, "Error Encountered"
Exit Sub
End If
Is there a better way to tell if items are selected, because I feel that the way I have it structured in my loop, the code will throw the error if everything isn't selected? Thank you in advance for any ideas, answers, or suggestions!
Note: The Listbox is populated by the click of another button on the userform which calls the following sub:
Sub FillLstBxCols()
Dim ListBx_Target As MSForms.ListBox
Dim rngSource As Range
Dim LR As Long
If Cells(2, 1).Value2 <> vbNullString Then
LR = Worksheets("New TRAX").Cells(Rows.Count, 2).End(xlUp).Row
'Set reference to the range of data to be filled
Set rngSource = Worksheets("New Trax").Range("A" & 2 & ":" & "B" & LR)
'Fill the listbox
Set ListBx_Target = UserForm_Finder.ListBx_TblsCols
With ListBx_Target
.RowSource = rngSource.Address
End With
End If
End Sub
Hard to say without sample data and expected results, but I think this is what you're looking for:
Private Sub btnConcat_Click()
Dim ws As Worksheet
Dim bSelected As Boolean
Dim sConcat As String
Dim i As Long, lRowIndex As Long
Set ws = ActiveWorkbook.Sheets("New TRAX")
lRowIndex = 1
bSelected = False
sConcat = Trim(Me.txtConcat.Text)
If Len(sConcat) = 0 Then sConcat = Trim(ws.Cells(2, "A").Value)
If Len(sConcat) = 0 Then
MsgBox "You must Search for a Table or Column first.", vbExclamation, "Error Encountered"
Exit Sub
End If
For i = 0 To Me.ListBx_TblsCols.ListCount - 1
If Me.ListBx_TblsCols.Selected(i) Then
If bSelected = False Then
bSelected = True
ws.Range("C2", ws.Cells(ws.Rows.Count, "C")).Clear 'clear previous concat results (delete this line if not needed)
End If
lRowIndex = lRowIndex + 1
ws.Cells(lRowIndex, "C").Value = sConcat & "." & Me.ListBx_TblsCols.List(i)
End If
Next i
If bSelected = False Then MsgBox "Must select at least one item from the list"
End Sub

VBA User from Text boxes not populating from worksheet

I have a list box which details inquiries and when the double click is used on a line in the list box, a second userform opens to allow the information to update, the issues i am having is the date which is supposed to come from the 13 & 14th columns is not transferring back to the text box:
.Offset(0, 13).Value, txtnotes.Value, _
.Offset(0, 14).Value, txtdtime.Value)
The other combo boxes and text boxes are taking retrieving the correct data, but it is these final boxes which will not go.
here is the complete code:
Private Sub UserForm_Initialize()
'dim the variables
Dim i As Integer
On Error Resume Next
'find the selected list item
i = frmenqnew.lstenq.ListIndex
'add the values to the text boxes
Me.txtenqup.Value = frmenqnew.lstenq.Column(0, i)
Me.txtcustup.Value = frmenqnew.lstenq.Column(1, i)
Me.cboup3.Value = frmenqnew.lstenq.Column(4, i)
Me.cboup4.Value = frmenqnew.lstenq.Column(5, i)
Me.cboup5.Value = frmenqnew.lstenq.Column(6, i)
Me.cboup6.Value = frmenqnew.lstenq.Column(7, i)
Me.txtrev.Value = frmenqnew.lstenq.Column(9, i)
Me.txtnotes.Value = frmenwnew.lstenq.Column(13, i)
Me.txtdtime.Value = frmenwnew.lstenq.Column(14, i)
With cboup5
.AddItem "Active"
.AddItem "Dormant"
.AddItem "Lost"
.AddItem "Sold"
End With
With cboup6
.AddItem "Drawing"
.AddItem "Appraisal"
.AddItem "Verification"
.AddItem "Presenting"
End With
On Error GoTo 0
End Sub
Private Sub cmdUpdate_Click()
' To write edited info of userform2 to Sheets("Data")
Dim LastRow As Long
Dim ABnum As Double
Dim ABrng As Range
Dim WriteRow As Long
'error statement
On Error GoTo errHandler:
'hold in memory and stop screen flicker
Application.ScreenUpdating = False
' Make sure we're on the right sheet
With Sheets("Data")
' Get the last row used so can set up the search range
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
' Set the range to search for the AB number
Set ABrng = .Range("A1:A" & LastRow)
' Get the AB number from what is selected on userform2
ABnum = txtenqup.Value
' Get the row of sheet for this AB number
WriteRow = Application.Match(ABnum, ABrng, 0)
' Make this AB number the active cell
With .Cells(WriteRow, 1)
'Check for changes
If Not hasValuePairsChanges(.Offset(0, 4).Value, cboup3.Value, _
.Offset(0, 5).Value, cboup4.Value, _
.Offset(0, 6).Value, cboup5.Value, _
.Offset(0, 7).Value, cboup6.Value, _
CDate(.Offset(0, 8).Value), Date, _
CDbl(.Offset(0, 9).Value), CDbl(txtrev.Value), _
.Offset(0, 13).Value, txtnotes.Value, _
.Offset(0, 14).Value, txtdtime.Value) Then
MsgBox "No Change in Data", vbInformation, ""
Exit Sub
End If
' Write in all the editable options
.Offset(0, 4) = cboup3.Value
.Offset(0, 5) = cboup4.Value
.Offset(0, 6) = cboup5.Value
.Offset(0, 7) = cboup6.Value
.Offset(0, 8) = Date
.Offset(0, 9) = txtrev.Value
.Offset(0, 13) = txtnotes.Value
.Offset(0, 14) = txtdtime.Value
Sheets("Archive").Range("A" & Rows.Count).End(xlUp)(2).Resize(, 14).Value = .Resize(, 14).Value
End With
End With
' Filter the Data
FilterMe
' Close the form
Unload Me
MsgBox ("Enquiry E0" + Me.txtenqup.Text + " has been updated")
errHandler:
'Protect all sheets if error occurs
'Protect_All
'show error information in a messagebox
If Err.Number <> 0 Then
MsgBox "Error " & Err.Number & " just occured."
End If
End Sub
Function hasValuePairsChanges(ParamArray Args() As Variant) As Boolean
Dim n As Long
For n = 0 To UBound(Args) Step 2
If Not Args(n) = Args(n + 1) Then
hasValuePairsChanges = True
Exit Function
End If
Next
End Function
Any help much appreciated
Thanks

Resources