Excel VBA stop code where conditions are met - excel

I'm struggling getting my code to work.
I have a button on the excel sheet that when triggers
checks required fields value is 0, if not then message box and end code
checks if the reference number already exists on a master tab, if the reference exisits, message box and end code
if 1 and 2 pass then perform a copy and paste as values for 3 ranges then message box.
I've tried a number of options but can't get it to work
Function Mand() As Boolean
'checks that mandatory fields have been updated
If Sheets("INPUT").Range("C11") > 0 Then MsgBox "Mandatory Fields Missing" & vbNewLine & "Changes Not Saved!"
Mand = True
End Function
Function RecEx() As Boolean
'checks that the reference number does not exisit on the High Level master list
dup = WorksheetFunction.CountIf(Sheets("High_Level_List").Columns(1), Sheets("INPUT").Range("C17"))
If dup > 0 Then MsgBox "This Record Exists!!!" & vbNewLine & "If saving an update, use the Save Changes button"
RecEx = True
End Function
Sub RegisterNewRec()
' checks 2 functions, if either are TRUE then exit, otherwise update master
If Mand Then Exit Sub
If RecEx Then Exit Sub
End If
Dim rng As Range
Set rng = Sheets("INPUT").Range("AO2:CX2")
Sheets("High_Level_List").Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
'more code that updates master
MsgBox "Record added to Master"
End Sub

As I said in my comment, the End If doesn't need to be there:
If Mand Then Exit Sub
If RecEx Then Exit Sub
^ How the code should look
Alternatively you could use:
If Mand Or RecEx Then Exit Sub
You also need to make sure that you only set your function to True if the above is true by including the End If block:
Function Mand() As Boolean
If Sheets("INPUT").Range("C11") > 0 Then
MsgBox "Mandatory Fields Missing" & vbNewLine & "Changes Not Saved!"
Mand = True
End If
End Function
Function RecEx() As Boolean
dup = WorksheetFunction.CountIf(Sheets("High_Level_List").Columns(1), Sheets("INPUT").Range("C17"))
If dup > 0 Then
MsgBox "This Record Exists!!!" & vbNewLine & "If saving an update, use the Save Changes button"
RecEx = True
End If
End Function
The problem is that you were setting the RecEx and the Mand to true either way.

Related

Excel VBA Textbox_Exit Event Handler

At a road block here. Simple user form using three text boxes, one for user id, two to enter serial number using hand scanner. User loads excel file, userform.show loads, user enters id then simple validation to verify numberic number, then focus set on first textbox, user scans barcode to input serial number, again simple validation to ensure numeric and length, same with last textbox, scan serial number, validate first textbox entry matches second textbox entry.
Hand scanner is used to input serial number and also returns a "return carriage" character; e.g. enter button press after serial number scan.
Using "return carriage" to fire textbox_exit event handler. Issue is very intermittent but consistent. I load userform, input data, when record is complete, data is transferred to object worksheet. However, when troubleshooting, I initially open workbook and userform, create a few records, save, and close. Everything works well and data is recorded and archived. Issue generally arises when i load workbook a second time, enter data for one record, save, and begin second record. Once serial number is entered into first textbox, exit event never fires using "return carriage". I can manually transfer focus to other objects; e.g. diff textbox, but the overall operation is not as expected.
I have tried inserting application.eventhandler=true commands, different event handlers, as well as numerous code changes; e.g. exit sub at end of IF statements, to make this work.
Thought I would reach out to the community for some feedback. FYI, issues still arises if I simulate hand scanner using copy/paste and enter key.
Example of exit event handler for first serial textbox below.
Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Cancel = False
If Not IsNumeric(SerialIn.Value) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
MsgBox Msg, vbCritical, "Warning" 'display msg
Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Exit Sub
Else
If Not Len(SerialIn.Value) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
MsgBox Msg, vbCritical, "Warning"
Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Exit Sub
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
Me.SerialOut.SetFocus
Exit Sub
End If
End If
End Sub
New code:
Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Cancel = ValidateSerialIn(SerialIn)
End Sub
Function ValidateSerialIn(ByVal TextBox As Object) As Boolean
If Not IsNumeric(SerialIn.Value) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning" 'display msg
SerialIn.SetFocus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
ValidateSerialIn = True
Else
If Not Len(SerialIn.Value) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning"
'Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
ValidateSerialIn = True
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
ValidateSerialIn = False
End If
End If
End Function
Third go using Tim's TextBox_Change solution:
Private Sub SerialIn_Change()
Dim v
v = ScannedValue1(SerialIn.Text)
If Len(v) > 0 Then
If Not IsNumeric(v) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning" 'display msg
SerialIn.Text = vbNullString
Else
If Not Len(v) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning"
SerialIn.Text = vbNullString
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
SerialOut.SetFocus
End If
End If
End If
End Sub
'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue1(vIn) As String
Dim rv As String
If Right(vIn, 2) = vbCrLf Then
ScannedValue1 = Replace(vIn, vbCrLf, "")
ElseIf Right(vIn, 1) = vbLf Then
ScannedValue1 = Replace(vIn, vbLf, "")
End If
End Function
If you want to detect the "Enter" from the scanner then use the Change event to check if the textbox value ends with vbCrLf or vbLf (in that order): if it does, then trigger the "scan" action.
Note you need to set your textbox to "multiline=true" and "EnterKeyBehaviour = true" in order for the Change event to capture the enter key.
Private Sub TextBox1_Change()
Dim v
v = ScannedValue(TextBox1.Text)
If Len(v) > 0 Then
TriggerScanAction v
TextBox1.Value = ""
End If
End Sub
'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue(vIn) As String
Dim rv As String
If Right(vIn, 2) = vbCrLf Then
ScannedValue = Replace(vIn, vbCrLf, "")
ElseIf Right(vIn, 1) = vbLf Then
ScannedValue = Replace(vIn, vbLf, "")
End If
End Function
'execute some action triggered by a scanned value
Sub TriggerScanAction(v)
MsgBox "You scanned " & v
End Sub
The Exit event has more to it than meets the eye. On most forms, one enters a value in a textbox and then clicks "OK", a command button. Tbx.Exit event occurs. It also occurs if you click anywhere else, such as a button to close the form. In your system the CR triggers the event as well, and that would appear to be the problem.
When a CR or TAB is entered in your Tbx the form's tapping sequence takes over. The exit occurs, followed by the enter event of the next control in your tapping order. (Compare that to the manual change of focus that occurs when the user determines the next control.)
So, the solution should be not to use the Exit event but to let the CR initiate a change of focus, using the tapping order setting, which lands the focus on an "OK" button, then let that button's Enter event trigger its Click event (if it doesn't do that by default).
You probably want a cycle there, where the CR triggers the worksheet entry and the focus comes back to the Tbx. That's one more reason not to use the Exit event because you don't want an entry made in the worksheet when you exit the Tbx to close the form.
However, perhaps your form doesn't have or need an "OK" button. In that case I would recommend the BeforeUpdate event of the Tbx. Both Exit and BeforeUpdate occur in close succession. The sequence isn't important however (though that's not the reason why I forgot it :-)) but their nature. Use the exit event in the context of form control, setting focus or reacting to focus change. BeforeUpdate obviously refers to data. Each of these events is fine tuned to its own task and therefore does it better than the other.

Handling incorrect password runtime errors

First time post but a long time user! Firstly I wanted to say thank you to every for all the code feedback you guys put on posts. It's helped me develop my VBA code more than you can imagine!
Ok so the question:
Background:
I'm developing a VBA focused addin for myself and colleagues to use. Part of this is include functions that you would except in Excel but aren't there. Some of these were quite easy to do (ie invert filters) but some are proving more difficult. This is one of those examples.
Issue:
The following code is meant to loop through the users selection of sheets, apply a user defined password or remove the existing one. Part of the function is to capture passwords that can't be removed (ie becuase the user entered an incorrect password). It works great for the first error occurrence but throughs up the runtime error (1004) for the second and repeating ones after. I don't much much experience with runtime errors handling (try to avoid errors!) but I can't get this to work. Any ideas /help to stop the runtime error popping up would be great.
Code:
Dim SHT As Worksheet, Password As String, SHT_Names(0 To 30) As String
'PREP
'DISABLE APPLICATION FUNCTIONS
Call Quicker_VBA(False)
Application.EnableEvents = False
'USER PASSWORD OPTION
Password = InputBox("Please enter a password (leave blank for no password)", "Password")
'USER INFORMATION MESSAGES SETUP
MSG_Protect = "Added to-"
Protect_check = MSG_Protect
MSG_Unprotect = "Removed from-"
Unprotect_check = MSG_Unprotect
MSG_unable = "Unable to remove protection from-"
Unable_check = MSG_unable
'ID SHEETS SELECTED
For Each SHT In ActiveWindow.SelectedSheets
a = a + 1
SHT.Activate
SHT_Names(a) = SHT.name
Next
'MAIN
HomeSHT = ActiveSheet.name
'PROTECT SHEETS SELECTED BY USER
For b = 1 To a
Sheets(SHT_Names(b)).Select
Set SHT = ActiveSheet
'ENABLE OR REMOVE PROTECTION FROM SELECTED SHEET
If SHT.ProtectContents Then
On Error GoTo Password_FAIL
Application.DisplayAlerts = False
SHT.Unprotect Password
On Error GoTo 0
MSG_Unprotect = MSG_Unprotect & vbNewLine & Chr(149) & " " & SHT.name
Else:
'ENABLE FILTER CHECK
FilterOn = False
If ActiveSheet.AutoFilterMode Then FilterOn = True
'PROTECT SHEET
SHT.Protect Password, AllowFiltering:=FilterOn
'UPDATE USER MESSAGE
MSG_Protect = MSG_Protect & vbNewLine & Chr(149) & " " & SHT.name & " - Users can: Select locked and unlocked cells"
If FilterOn = True Then MSG_Protect = MSG_Protect & " and use filters"
End If
200 Next
'INFORM USER
If Protect_check <> MSG_Protect Then msg = MSG_Protect & vbNewLine & "___________________" & vbNewLine
If Unprotect_check <> MSG_Unprotect Then msg = msg & MSG_Unprotect & vbNewLine & "___________________" & vbNewLine
If Unable_check <> MSG_unable Then msg = msg & MSG_unable
MsgBox msg, , "Protection summary"
'TIDY UP
Sheets(HomeSHT).Activate
'ENABLE APPLICATION FUNCTIONS
Call Quicker_VBA(True)
Exit Sub
Password_FAIL:
MSG_unable = MSG_unable & vbNewLine & Chr(149) & " " & SHT.name
Application.EnableEvents = False
GoTo 200
End Sub
At a quick glance, it seems that the problem is in the way you're handling your errors. You use the line On Error GoTo Password_FAIL to jump down to the error handler. The error handler logs some information and then jumps up to label '200'. I can't tell if the formatting is off, but it looks like the label for '200' points to Next, indicating that the loop should continue with the next sheet.
So, where's the problem? You never actually reset the original error. Three lines below On Error GoTo Password_FAIL you explicitly call On Error GoTo 0 to reset the error handler, but that line will never actually be reached in an error. The program will jump to the error handler, and then from there jump up to the loop iterator. Using the GoTo statement for control flow can easily lead to these types of issues, which is why most developers recommend against it.
I'll post some sample code below to show a different (potentially better) way to handle code exceptions. In the sample below, the code simply loops through all of the worksheets in the workbook and toggles the protection. I didn't include much of your logging, or the constraint that only the selected sheets be toggled. I wanted to focus on the error handling instead. Besides, from reading you code, it seems that you can manage more of the peripheral details. Send a message if there's still some confusion
Sub ToggleProtectionAllSheets()
Dim sht As Worksheet
Dim password As String
On Error Resume Next
password = InputBox("Please enter a password (leave blank for no password)", "Password")
For Each sht In ActiveWorkbook.Worksheets
If sht.ProtectContents Then
sht.Unprotect password
If Err.Number <> 0 Then
Err.Clear
MsgBox "Something did not work according to plan unprotecting the sheet"
End If
Else
sht.Protect password
If Err.Number <> 0 Then
Err.Clear
MsgBox "Something went wrong with protection"
End If
End If
Next sht
End Sub

Update cell with a value when form field is selected

I have an excel workbook with modeless form. The way it's setup is that: each sheet in the workbook has a tab in the form. Each field in these tabs is Linked to a cell in corresponding sheet. So when a value is changed/updated in the form, it is automatically updated in the relevant cell. The way I am doing this is by using the onChange event for each filed which call's a UDF that does the updating. My question, there are a lot of fields in the form and lots more to be added. Is there a way to update relevant cell when a field in the form is selected without having to add the call to a UDF in onChange event for each field?
I have tried using things like ControlSource but that only one way where it just updates the value in the form but doesn't update the value in the cell when form is updated.
As a side note, unfortunately I cannot share the form or the sheet but am willing to answer any questions
EDIT
Below is the function that updates the field:
Sub UpdateWorksheetValue(ByVal oObj As Object)
Dim oWS As Worksheet
Dim sCurrentValue As String
Dim iC As Long
' Lets check if tag is set
If Len(Trim(oObj.Tag)) = 0 Then
MsgBox "Empty tag found for '" & oObj.Name & "' field. Failed to update field value" & vbCrLf & vbCrLf & "Please contact system administrator with this information", vbCritical + vbOKOnly, "Update Failed"
Exit Sub
ElseIf Len(Trim(Mid(oObj.Tag, InStr(1, oObj.Tag, "¬") + 1))) = 0 Then
MsgBox "Tag for '" & oObj.Name & "' field does not include page title. Failed to update field value" & vbCrLf & vbCrLf & "Please contact system administrator with this information", vbCritical + vbOKOnly, "Update Failed"
Exit Sub
End If
' Set worksheet
Select Case LCase(Trim(Mid(oObj.Tag, InStr(1, oObj.Tag, "¬") + 1)))
Case "client identification"
Set oWS = oWB.Worksheets("Client Identification - Output")
Case "request details"
Set oWS = oWB.Worksheets("Request Details - Output")
Case "db responsible individuals"
Set oWS = oWB.Worksheets("DB Responsible Ind - Output")
Case "additional details"
Set oWS = oWB.Worksheets("Additional Details - Output")
End Select
' Set value
With oWS
' Lets check if tag is set
If Len(Trim(Mid(oObj.Tag, 1, InStr(1, oObj.Tag, "¬") - 1))) = 0 Then
MsgBox "Tag for '" & oObj.Name & "' field does not include corresponding cell information. Failed to update field value in '" & oWS.Name & "' worksheet" & vbCrLf & vbCrLf & "Please contact system administrator with this information", vbCritical + vbOKOnly, "Update Failed"
Exit Sub
End If
' Set the search value
.Range("Z1").Value = Mid(oObj.Tag, 1, InStr(1, oObj.Tag, "¬") - 1)
DoEvents
' If a row with tag text is not found, throw a message and exit sub
If Len(Trim(.Range("Z2").Value)) = 0 Then
MsgBox "Unable to find corresponding cell for '" & oObj.Name & "' field in '" & .Name & "' worksheet. Failed to update field value" & vbCrLf & vbCrLf & "Please ensure that the field's 'Tag' matches a cell in the sheet or contact system administrator", vbCritical + vbOKOnly, "Update Failed"
Exit Sub
End If
' Set field value
Select Case LCase(TypeName(oObj))
Case "textbox", "combobox"
.Range("B" & .Range("Z2").Value).Value = oObj.Value
Case "optionbutton"
If oObj.Value = True Then
.Range("B" & .Range("Z2").Value).Value = oObj.Caption
Else
.Range("B" & .Range("Z2").Value).Value = ""
End If
Case "listbox"
' First lets the current cell value
sCurrentValue = .Range("B" & .Range("Z2").Value).Value
' Now lets build the string for the cell
For iC = 0 To oObj.ListCount - 1
If oObj.Selected(iC) And InStr(1, sCurrentValue, oObj.List(iC)) = 0 Then
sCurrentValue = sCurrentValue & "/" & oObj.List(iC)
ElseIf Not oObj.Selected(iC) And InStr(1, sCurrentValue, oObj.List(iC)) > 0 Then
sCurrentValue = Replace(sCurrentValue, "/" & oObj.List(iC), "")
End If
Next
' And finally, set the value
.Range("B" & .Range("Z2").Value).Value = sCurrentValue
End Select
End With
' Clear object
Set oWS = Nothing
End Sub
EDIT 2
I now have a class called formEventClass as suggested by David. Contents of the class are:
Option Explicit
Public WithEvents tb As MSForms.TextBox
Private Sub tb_Change()
UpdateWorksheetValue (tb)
End Sub
But when I make a change in any given text box, cells are not updated (as per David's suggestion, I've removed the call to UpdateWorksheetValue in text box onChange event. Cells are not updated even when I tab out of the field. As this is working for David, I suspect I am missing something here
If you want to get fancy using WithEvents...
Create a Class Module and name it tbEventClass. Put the following code in this module.
Option Explicit
Public WithEvents tb As MSForms.TextBox
Private Sub tb_Change()
Call UpdateWorksheetValue(tb)
End Sub
This defines a custom class (tbEventClass) which is responsive to the events of it's tb property which is a TextBox. You'll need to map your textboxes to instances of this class during the form's Initialize event:
Public textbox_handler As New Collection
Private Sub UserForm_Initialize()
Dim ctrl As Control, tbEvent As tbEventClass
For Each ctrl In Me.Controls
If TypeName(ctrl) = "TextBox" Then
Set tbEvent = New tbEventClass
Set tbEvent.tb = ctrl
textbox_handler.Add tb
End If
Next
End Sub
Important: You will either need to remove or modify the Change event handlers in the UserForm module to avoid duplicate calls to the "update" procedure. If the only thing going on in those event handlers is the call to your update macro, just get remove the event handlers entirely, they're fully represented by the tbClass. If those events contain other code that does other stuff, just remove or comment out the line(s) that call on your update function.
Update:
This is working for me with the controls within a MultiPage and required ZERO changes to the implemented code above.

How we can show the value of adjacent cell value if checkbox left unchecked?

I am new to VBA Macro. There is a list of steps to be followed to submit a project and each step has a checkbox in adjacent cell. I want to show the value if a checkbox is left unchecked. I haven't wrote any code. I am new to this. Need help.
Yes, i want to use the Message box, to show the value of the cell unchecked after click of submit button as shown in the snapshot.
I wrote this module, but its lengthy.
Sub AllChecked()
If Range("d3").Value = 18 Then
MsgBox "Project ready for upload"
End If
If Range("c3").Value = False Then
MsgBox "Please review the cover sheet"
End If
If Range("c4").Value = False Then
MsgBox "Please review the processor's notes"
End If
If Range("c5").Value = False Then
MsgBox "Please Review the project map"
End If
If Range("c6").Value = False Then
MsgBox "Please Check the orientation"
End If
If Range("c7").Value = False Then
MsgBox "Please Check for missing data"
End If
If Range("c8").Value = False Then
MsgBox "Please Check for illegal movements"
End If
If Range("c9").Value = False Then
MsgBox "Analyze the data in 2 to 3-hour increments as well as 15-minute increments"
End If
If Range("c10").Value = False Then
MsgBox "Please check the date of collection"
End If
If Range("c11").Value = False Then
MsgBox "Please Check for abnormal peaks or valleys in the datasets"
End If
If Range("c12").Value = False Then
MsgBox "Please give spot checks if necessary"
End If
If Range("c13").Value = False Then
MsgBox "Make small adjustments if necessary"
End If
If Range("c14").Value = False Then
MsgBox "Please checking historical data if it exists"
End If
If Range("c15").Value = False Then
MsgBox "Please Check for the diffrent templets as per the project series"
End If
If Range("c16").Value = False Then
MsgBox "Please Make note for extra leg (include/exclude)"
End If
If Range("c17").Value = False Then
MsgBox "Before removing the side walk from peds count check the rotation and coversheet if client required or not"
End If
If Range("c18").Value = False Then
MsgBox "Sketches? (Always for the 3000 jobs,some with requested Project)(review the processer sketches)"
End If
If Range("c19").Value = False Then
MsgBox "Check for data patterns in the datasets for two successive intervals having same total volume and each movement has similarities etc"
End If
If Range("c20").Value = False Then
MsgBox "Check for data patterns in the datasets for two successive intervals having same total volume and each movement has similarities etc"
End If
End Sub
You can loop through Range("C3:C20") testing the values and building the message. This way you'll only have one Msgbox.
Sub AllChecked()
Dim msg As String
Dim c As Range
If Range("d3").Value = 18 Then
MsgBox "Project ready for upload"
Else
For Each c In Range("C3:C20")
If c.Value = FASLE Then msg = msg & c.Offset(0, -1).Value & vbCrLf
Next
MsgBox msg, vbInformation, "Fill in these fields before continuing"
End If
End Sub

EXCEL VBA WorksheetFunction.CountIf() in a SELECT CASE

I know that it is possible to use If statement but out of curiosity, as mentioned in the title, is it possible to use SELECT statement to do something as BOLDED below? I've submitted my whole Sub as below for better understanding:
Sub addNewCust_Click()
Dim response As String
response = Application.InputBox(prompt:="", Title:="New customer name", Type:=2)
Select Case response
Case False
Exit Sub
'Check if response is not an empty value AND record found in "CustomerList"
Case Is <> "" & WorksheetFunction.CountIf(Worksheets("CustomerList").Range("B:B"), response) > 0
MsgBox "'" & response & "' already exists on this sheet."
Call addNewCust_Click
'Check if response is not an empty value and record is not found in "Customerlist"
Case Is <> "" & WorksheetFunction.CountIf(Worksheets("CustomerList").Range("B:B"), response) < 1
Sheets("CustomerList").Range("B1048576").End(xlUp).Offset(1, 0).Value = response
MsgBox "'" & response & "' successfully entered!"**
Case Else
MsgBox "Field is empty!"
Call addNewCust_Click
End Select
End Sub
Like this?
Sub addNewCust_Click()
Dim response As String
response = Application.InputBox(prompt:="", Title:="New customer name", Type:=2)
Select Case response
Case False: Exit Sub
'Check if response is not an empty value AND record found in "CustomerList"
Case Is <> ""
If WorksheetFunction.CountIf(Worksheets("CustomerList").Range("B:B"), response) > 0 Then
MsgBox "'" & response & "' already exists on this sheet."
Call addNewCust_Click
Else
Sheets("CustomerList").Range("B1048576").End(xlUp).Offset(1, 0).Value = response
MsgBox "'" & response & "' successfully entered!"
End If
Case Else
MsgBox "Field is empty!"
Call addNewCust_Click
End Select
End Sub
FOLLOWUP (From Comments)
Select Case is considered to be faster than If-Endif but for such a small scenario, the efficiency comparison is futile. What is more important is how you write the code
Below is another way. I love this way as things are broken down into smaller parts and everything is declared properly. I am not touching error handling below. See this for detailed analysis.
The below method is useful because
when you are looking at your code (say maybe after an year) and you know exactly what is happening since the code is commented.
Easy to maintain the code. For example if the Sheet name changes then you have to change it only at one place. The alternative is to also use Codenames
You can use the same code across all Excel platforms. If you hardcode your range, Ex: Range("B1048576") then the above code will not work in Excel 2003.
Sample Code
Sub addNewCust_Click()
Dim ws As Worksheet
Dim Lrow As Long
Dim response
'~~> Set the relevant worksheet
Set ws = ThisWorkbook.Worksheets("CustomerList")
With ws
Do
'~~> Get user response
response = Application.InputBox(prompt:="", Title:="New customer name", Type:=2)
Select Case response
Case False: Exit Sub '<~~ If user presses cancel or closes using 'X'
Case "": MsgBox "Field is empty!" '<~~ If user enters a blank entry
Case Else
'~~> Check if the entry exists
If WorksheetFunction.CountIf(.Range("B:B"), response) > 0 Then
MsgBox "'" & response & "' already exists on this sheet."
Else
'~~> Get last Row
Lrow = .Range("B" & .Rows.Count).End(xlUp).Row + 1
'~~> Add the new entry
.Range("B" & Lrow).Value = response
MsgBox "'" & response & "' successfully entered!"
Exit Do 'OR Exit Sub (As Applicable)
End If
End Select
Loop
End With
End Sub

Resources