Excel VBA restarting same Subroutine within itself based on VbMsgBoxResult - excel

I'm trying to get my Sub to restart based on MsgBoxReults. The code I have doesn't contain any errors, but won't restart based on the users choice (hopefully, having an IF statement within another IF isn't the issue)
Please assist.
Sub ContinueWeatherList()
Dim Weather As String
'Assigning a Message Box result as a Variable for Yes/No
Dim MoreWeather As VbMsgBoxResult
Weather = InputBox("Type in the weather for " & Range("C1").End(xlDown) + 1)
If Weather = "" Then
MsgBox ("No data entered. Your response has not been recorded"), vbExclamation
Else
Range("C1").End(xlDown).Offset(1, 0).Value = Range("C1").End(xlDown) + 1
Range("A1").End(xlDown).Offset(1, 0).Value = Range("A1").End(xlDown) + 1
Range("B1").End(xlDown).Offset(1, 0).Value = Weather
Columns("A:C").EntireColumn.AutoFit
MsgBox "Thank you for entering your data " & vbNewLine & "Would you like to enter another?", vbYesNo
'Using IF statement to decide what happens for each condition
If MoreWeather = vbYes Then
''Call' command won't reinitiate Sub / *NEED TO FIX*
Call ContinueWeatherList
Else
MsgBox "Thank you for you input.", vbInformation
End If
End If
End Sub

Try the code below. You need to setup a variable to get the feedback from the VBYesNo MsgBox.
Option Explicit
Sub ContinueWeatherList()
Dim Weather As String
'Assigning a Message Box result as a Variable for Yes/No
Dim MoreWeather As Variant
' add label to restart to
ContinueWeatherList_Restart:
Weather = InputBox("Type in the weather for " & Range("C1").End(xlDown) + 1)
If Weather = "" Then
MsgBox ("No data entered. Your response has not been recorded"), vbExclamation
Else
Range("C1").End(xlDown).Offset(1, 0).Value = Range("C1").End(xlDown) + 1
Range("A1").End(xlDown).Offset(1, 0).Value = Range("A1").End(xlDown) + 1
Range("B1").End(xlDown).Offset(1, 0).Value = Weather
Columns("A:C").EntireColumn.AutoFit
MoreWeather = MsgBox("Thank you for entering your data " & vbNewLine & "Would you like to enter another?", vbYesNo)
'Using IF statement to decide what happens for each condition
If MoreWeather = vbYes Then
' use GOTo command and label to reinitiate the sub
GoTo ContinueWeatherList_Restart
Else
MsgBox "Thank you for you input.", vbInformation
End If
End If
End Sub

This moves the loop to a calling sub:
Sub EnterWeatherListItems()
Dim MoreWeather As VbMsgBoxResult
MoreWeather = vbYes
Do While MoreWeather = vbYes
Call FillWeatherList
'Assigning a Message Box result as a Variable for Yes/No
'Using IF statement to decide what happens for each condition
MoreWeather = MsgBox("Thank you for entering your data " & vbNewLine & "Would you like to enter another?", vbYesNo)
Loop
MsgBox "Thank you for you input.", vbInformation
End Sub
Sub FillWeatherList()
Dim Weather As String
Weather = InputBox("Type in the weather for " & Range("C1").End(xlDown) + 1)
If Weather = "" Then
MsgBox ("No data entered. Your response has not been recorded"), vbExclamation
Else
ActiveSheet.Range("C1").End(xlDown).Offset(1, 0).Value = ActiveSheet.Range("C1").End(xlDown) + 1
ActiveSheet.Range("A1").End(xlDown).Offset(1, 0).Value = ActiveSheet.Range("A1").End(xlDown) + 1
ActiveSheet.Range("B1").End(xlDown).Offset(1, 0).Value = Weather
Columns("A:C").EntireColumn.AutoFit
End If
End Sub

From #Shai Rado's answer but without gotos or variants
Option Explicit
Sub ContinueWeatherList()
Dim Weather As String
'Assigning a Message Box result as a Variable for Yes/No
Dim NoMoreWeather As Boolean
' Loop until user says otherwise
Do Until NoMoreWeather = vbNo
Weather = InputBox("Type in the weather for " & Range("C1").End(xlDown) + 1)
If Weather = "" Then
MsgBox ("No data entered. Your response has not been recorded"), vbExclamation
Else
Range("C1").End(xlDown).Offset(1, 0).Value = Range("C1").End(xlDown) + 1
Range("A1").End(xlDown).Offset(1, 0).Value = Range("A1").End(xlDown) + 1
Range("B1").End(xlDown).Offset(1, 0).Value = Weather
Columns("A:C").EntireColumn.AutoFit
NoMoreWeather = MsgBox("Thank you for entering your data " & vbNewLine & "Would you like to enter another?", vbYesNo)
End If
Loop
End Sub

Related

Only Certain UserForm Fields Mandatory While Others are "And Or" Excel VBA

I hope you are all keeping safe!
Within my UserForm, there are multiple ComboBoxs and TextBoxs.
When the Command Button is clicked Ideally what I would like to achieve is that: ComboBox2 & Textbox6 are a mandatory requirement, while having Either textbox2 and or (one or the other) Textbox3 also a mandatory requirement, before the form copies into the workbook.
The following code makes the ComboBox2 field mandatory but I just don’t know how to make either textbox2 and OR Textbox3 a requirement. I've just started to learn a little about Excel VBA, so any help is greatly appreciated! :)
If ComboBox2.Value = "" And ComboBox3.Value = "" And TextBox6.Value = "" Or TextBox16.Value = "" Or TextBox17.Value = "" Then
MsgBox "You must select a: Category/Type, a Description, and a Start Date" & vbCrLf & "And enter either an: Expenses or Income Amount." & vbCrLf & "Please check your entries and try again.", vbCritical
Exit Sub
End If
When validating inputs on UserForms there are a few ways I do it.
Here is an example from an input form that requires all but 1 field to be completed:
The userform:
And the validation in the code behind:
Dim Code As String
Dim Description As String
Dim Qty As String
Dim Min As String
Dim ProductType As String
Dim Supplier As String
Dim StockMinimums As String
With Me
Code = .txtCodeLG.Text
Description = .txtDescriptionLG.Text
Qty = .txtQtyLG.Value
Min = .txtMinLG.Value
If .chkEMG80.Value = True Then
ProductType = .chkEMG80.Caption
ElseIf .chkUCP100.Value = True Then
ProductType = .chkUCP100.Caption
ElseIf .chkEMGLicences.Value = True Then
ProductType = .chkEMGLicences.Caption
ElseIf .chkUCPLicences.Value = True Then
ProductType = .chkUCPLicences.Caption
End If
Dim opt As Control
For Each opt In Me.Controls
If TypeName(opt) = "OptionButton" Then
If opt.Value = True Then
Supplier = opt.Caption
Else
'Do nothing
End If
End If
Next opt
End With
If Me.chkMinimumsSheet.Value = True Then
StockMinimums = "Yes"
ElseIf Me.chkMinimumsSheet.Value = False Then
StockMinimums = "No"
End If
'--------------------------------------Error checking-------------------------------------
Dim ErrorString As String
If Code = "" Then
ErrorString = ErrorString + "Please enter a value into the 'Code' box." & vbNewLine
End If
If Description = "" Then
ErrorString = ErrorString + "Please enter a value into the 'Description' box." & vbNewLine
End If
'If Qty = "" Then
' ErrorString = ErrorString + "Please enter a value into the 'Quantity' box." & vbNewLine
'End If
If Min = "" Then
ErrorString = ErrorString + "Please enter a value into the 'Minimum' box." & vbNewLine
End If
If ProductType = "" Then
ErrorString = ErrorString + "Please choose a 'Product Type'." & vbNewLine
End If
If Supplier = "" Then
ErrorString = ErrorString + "Please select a 'Supplier'." & vbNewLine
End If
If Not ErrorString = "" Then
MsgBox ErrorString + vbNewLine & "Danger to manifold.", vbCritical, "Values Missing"
Exit Sub
End If
And if the user clicks submit without filling out the required fields it displays a descriptive message advising what is missing (heres the msgbox when nothing is filled in):
you can use an "or" or "and" statement like you would in non vba excel, its just a little different formatting. But you are exactly on the right path!
Basically if both are blank, then a message would pop up requiring a value in one of the boxes. If one or both are filled in, then good. I.E.
if textbox2.value = "" and textbox3.value = "" then
msgbox "You must enter a value in textbox 2 and/or 3", vbCritical
exit sub
end if
for an "or" statement, just replace "and" with "or"
Edit to add:
for going thru multiple iterations thru your userform for data validation and checking if boxes are filled in, etc. I would start top to bottom, and do a check for each one.
if textbox1.value = "" then
msgbox "Please fill in " & textbox1.name (or .tag or some other way to identify the item), vbcritical, "Error"
exit sub
elseif combobox2.value = "" then
msgbox "Please fill in " & combobox2.name, vbcritical, "Error"
exit sub
elseif textbox6.value = "" then
msgbox "Please fill in " & textbox6.name, vbcritical, "Error"
exit sub
elseif textbox2.value = "" or textbox3.value="" then
msgbox "Please fill in either textbox 2 or 3", vbcritical, "Error"
exit sub
end if
If they are simple, and have a way to loop as described by another gentleman, you can use a generic formula such as
for i=1 to 5
if me.controls("Textbox" & i).value = "" then
msgbox "Please fill in " & me.controls("textbox" & i).name, vbcritical, "Error"
exit sub
exit for
end if
next i
I would perhaps use a combination if you have a lot of boxes. Say there are 10 mandatory boxes, I can use the loop thru all 10 mandatory, and then just use individual if then statements using the "or" statement to check those that are one or the other

VBA Excel Change Value in Field

I have an excel table with a column named "Completed?" that users select Yes or No from the drop down. If they Select Yes a Message Box using vbOKCancel pops up. If they confirm Yes that part is working so far, but if anything else happens (they hit Cancel, or X out, etc) I want this field to be changed to "No" - this is what I'm struggling with.
It seems like it should be simple - any ideas?
If Target.Column = 3 And Target.Value = "Yes" Then
Dim answer As Integer
answer = MsgBox("Are you sure you want to mark this as Completed? This will move the record to the Completed Tab and cannot be undone.", vbOKCancel + vbCritical, "CRITICAL WARNING")
If answer = vbOK Then MsgBox ("OK")
'need help with this next row
Else: Target.Value = "No"
End If
End Sub
Fundimentaily, you issue is missuse of the If Then Else End IF structure. (you are mixing Multi Line and Single Line syntax)
See here for more details
There are some other issues too, see inline comments
Private Sub Worksheet_Change(ByVal Target As Range)
Dim answer As VbMsgBoxResult ' use correct data type
Dim rng As Range, cl As Range
On Error GoTo EH ' ensure events get turned back on
Application.EnableEvents = False ' prevent event cascade
Set rng = Application.Intersect(Target, Me.Columns(3)) ' get all cells in column 3 that changed
For Each cl In rng ' process each changed cell
If LCase(cl.Value) = "yes" Or LCase(cl.Value) = "y" Then ' case insensitive
answer = MsgBox("Are you sure you want to mark row " & cl.Row & " as Completed?" & vbNewLine & vbNewLine & "This will move the record to the Completed Tab and cannot be undone.", vbOKCancel + vbCritical, "CRITICAL WARNING")
If answer = vbOK Then
cl.Value = "Yes" ' Standardise case
' MsgBox "OK" ' this is a bit annoying
Else
cl.Value = "No"
End If
End If
Next
EH:
Application.EnableEvents = True
End Sub
try this:
If Target.Column = 3 And Target.Value = "Yes" Then
Dim answer As Integer
answer = MsgBox("Are you sure you want to mark this as Completed? " & _
"This will move the record to the Completed Tab and cannot be undone.", vbOKCancel + vbCritical, "CRITICAL WARNING")
If answer = vbOK Then
MsgBox ("OK")
Else
Target.Value = "No"
End If
End If

Sending Data from Word Into Excel: Run-time error: '424' Object Required

I am trying to send data to Excel from Word after an email is sent. I have the email and the rest of it working. Now, I am trying to get the part with Excel working.
Private Sub btnGenerateEmail_Click()
'Instatiate Application Objects (using late binding)
Dim App As Object
Dim Msg As Object
Const olMailItem As Long = 0
'Declare Form Variables
Dim EmplName As String: EmplName = Me.frmEmployeeName
Dim IncidentDesc As String: IncidentDesc = Me.frmIncidentDescription
Dim EmplTrain As String: EmplTrain = Me.frmEmployeeTraining
Dim FaceOnRack As String: FaceOnRack = Me.frmFaceOnRack
Dim DrawingProb As String: DrawingProb = Me.frmDrawingProblem
Dim JobNum As String: JobNum = Me.frmJobNumber
Dim DrwNum As String: DrwNum = Me.frmDrawingNumber
Dim FaceDesc As String: FaceDesc = Me.frmFaceDescription
Dim Qty As String: Qty = Me.frmQty
Dim StockOrNon As String: StockOrNon = Me.frmStockOrNon
Dim FaceReplace As String: FaceReplace = Me.frmFaceReplace
'Set Application Objects (using late binding)
Set App = CreateObject("Outlook.Application")
Set Msg = App.CreateItem(olMailItem)
'Data validation
If IsNull(EmplName) Or EmplName = "" Then
MsgBox ("Please enter the employee's name."), vbCritical
Exit Sub
End If
If IsNull(IncidentDesc) Or IncidentDesc = "" Then
MsgBox ("Please describe how the face was broken."), vbCritical
Exit Sub
End If
If IsNull(EmplTrain) Or EmplTrain = "" Then
MsgBox ("Does the employee need more training to avoid these kind of incidents in the future?"), vbCritical
Exit Sub
End If
If IsNull(FaceOnRack) Or FaceOnRack = "" Then
MsgBox ("Was the already broken when on rack?"), vbCritical
Exit Sub
End If
If IsNull(DrawingProb) Or DrawingProb = "" Then
MsgBox ("Was the face scrapped because of an issue with the drawing/art?"), vbCritical
Exit Sub
End If
If IsNull(JobNum) Or JobNum = "" Then
MsgBox ("Please enter the job number or traveler number."), vbCritical
Exit Sub
End If
If IsNull(DrwNum) Or DrwNum = "" Then
MsgBox ("Please enter the drawing number."), vbCritical
Exit Sub
End If
If IsNull(FaceDesc) Or FaceDesc = "" Then
MsgBox ("Please enter a description of the face being scrapped."), vbCritical
Exit Sub
End If
If IsNull(Qty) Or Qty = "" Then
MsgBox ("Please enter the quantity being scrapped."), vbCritical
Exit Sub
End If
If IsNull(StockOrNon) Or StockOrNon = "" Then
MsgBox ("Is the face stock or non-stock?"), vbCritical
Exit Sub
End If
If IsNull(FaceReplace) Or FaceReplace = "" Then
MsgBox ("Does this face need to be replaced?"), vbCritical
Exit Sub
End If
'Compose HTML Message Body
Dim HTMLContent As String
HTMLContent = "<p style='font-family:Calibri; font-size:14px;'>This email is an autogenerated scrap face incident report.</p>" _
& "<table style='font-family:Calibri; font-size:14px;' width='75%' border='1' bordercolor='black' cellpadding='5'>" _
& "<tr><td width='65%'>Employee Name</td><td>" & EmplName & "</td></tr>" _
& "<tr><td>How was the face broken?</td><td>" & IncidentDesc & "</td></tr>" _
& "<tr><td>Does employee in question need more training to prevent future incidents?</td><td>" & EmplTrain & "</td></tr>" _
& "<tr><td>Was the face found on the rack already broken?</td><td>" & FaceOnRack & "</td></tr>" _
& "<tr><td>Was the face scrapped because of an issue with the drawing/art?</td><td>" & DrawingProb & "</td></tr>" _
& "<tr><td>Job/Traveler Number:</td><td>" & JobNum & "</td></tr>" _
& "<tr><td>Drawing Number:</td><td>" & DrwNum & "</td></tr>" _
& "<tr><td>Face Description:</td><td>" & FaceDesc & "</td></tr>" _
& "<tr><td>Quantity</td><td>" & Qty & "</td></tr>" _
& "<tr><td>Stock or Non-Stock</td><td>" & StockOrNon & "</td></tr>" _
& "<tr><td>Does this face need to be replaced?</td><td>" & FaceReplace & "</td></tr>" _
& "</table>"
'Construct the email, pass parameter values, & send the email
With Msg
.To = "test#test.com"
.Subject = "Scrap Face Incident Report"
.HTMLBody = HTMLContent
.Display
'.Send
End With
'MAY NEED WORK
'Make sure the generated email is the active window
App.ActiveWindow.WindowState = olMaximized
'Application.Windows("Scrap Face Incident Report - Message (HTML)").Activate
'Create entry in scrap report
Dim ScrapReportFile As String
ScrapReportFile = "\\jacksonville-dc\common\SOP's for JV\WIP\Jonathan\JG - How to Replace Scrapped Faces\Scrap List (Faces).xlsx"
'File exists
If Dir(ScrapReportFile) <> "" Then
Dim ObjExcel As Object, ObjWb As Object, ObjWorksheet As Object
Set ObjExcel = CreateObject("EXCEL.APPLICATION")
Set ObjWb = ObjExcel.Workbooks.Open(ScrapReportFile)
ObjExcel.Visible = True
With ObjWb.Worksheets(3)
Dim lastrow As Long: lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
MsgBox (lastrow)
End With
'ObjWb.Worksheets(1).Range("A1") = "SOP Title: " & SOPTitle
'ObjWb.Worksheets(1).Range("F1") = "Date: " & Format(Now, "MM/dd/yyyy")
'ObjWb.Save
'ObjWb.Close
End If
'File does not exist; throw error
End Sub
On this section of code:
With ObjWb.Worksheets(3)
Dim lastrow As Long: lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
MsgBox (lastrow)
End With
I am trying to send the data gathered from the form and create a new row at the bottom of the sheet and then insert the data into specified columns. When I am doing the .Cells(.Rows.Count...etc I am getting an error.
Run-time error: '424' Object Required
Word doesn't know what xlUp is, because that is from the Excel object model.
Add the following line:
Const xlUp as Long = -4162
as per the documentation of xlUps corresponding value.

Search command button on userform not working correctly

I have a search button on a userform. I want 3 things to happen. If the user selects the Search button without putting any text in TextBox6, I want a msgbox to popup and tell them they need to add a customer code. If they enter a customer code that is not in the excel spreadsheet and select the Search button, I want a msgbox to popup and tell them that customer code doesn't exist. When they select OK I want TextBox6 to clear and the cursor to have focus set on TextBox6. If they enter a code in TextBox6 that is in the excel spreadsheet and select the Search button, I want that record to populate the userform. I am using the code below, and it works for scenario 1 and 2 above. But when the code exists in the excel spreadsheet, after it populates the userform the msgbox that says the that customer code doesn't exist still popsup. Can you adjust my code so that doesn't happen?
Private Sub CommandButton2_Click()
Dim ws As Worksheet
Dim strSearch As String
Dim aCell As Range
On Error GoTo Err
'validate text box
If TextBox6.Value = "" Then
MsgBox "Please Enter Customer Code"
Cancel = True
Me.TextBox6.SetFocus
Else
row_number = 0
Do
DoEvents
row_number = row_number + 1
items_in_review = Sheets("sheet1").Range("A" & row_number)
If items_in_review = TextBox6.Text Then
TextBox1.Text = Sheets("sheet1").Range("B" & row_number)
TextBox2.Text = Sheets("sheet1").Range("C" & row_number)
TextBox3.Text = Sheets("sheet1").Range("D" & row_number)
TextBox4.Text = Sheets("sheet1").Range("F" & row_number)
TextBox5.Text = Sheets("sheet1").Range("H" & row_number)
TextBox7.Text = Sheets("sheet1").Range("I" & row_number)
TextBox8.Text = Sheets("sheet1").Range("G" & row_number)
Me.TextBox7.Visible = True
Me.Label8.Visible = True
End If
Loop Until items_in_review = ""
MsgBox "Customer Code not Found"
Cancel = True
UserForm1.TextBox6.Value = ""
TextBox6.SetFocus
Exit Sub
Err:
MsgBox Err.Description
End If
End Sub
I prefer not to clear the search box if something is not found: as a user it's annoying if you have to retype the whole thing just because you made a typo...
Private Sub CommandButton2_Click()
Dim ws As Worksheet
Dim strSearch As String
Dim aCell As Range, v
On Error GoTo Err
'validate text box
v = Trim(TextBox6.Value)
If Len(v) = 0 Then
MsgBox "Please Enter Customer Code"
Cancel = True
Me.TextBox6.SetFocus
Exit Sub
End if
Set aCell = Sheets("sheet1").Range("A:A").Find(v, lookat:=xlWhole)
if not aCell is Nothing Then
with aCell.EntireRow
TextBox1.Text = .Cells(,"B").Value
TextBox2.Text = .Cells(,"C").Value
TextBox3.Text = .Cells(,"D").Value
TextBox4.Text = .Cells(,"F").Value
TextBox5.Text = .Cells(,"H").Value
TextBox7.Text = .Cells(,"I").Value
TextBox8.Text = .Cells(,"G").Value
end with
Me.TextBox7.Visible = True
Me.Label8.Visible = True
else
MsgBox "Customer Code not Found"
Cancel = True
'UserForm1.TextBox6.Value = "" 'don't do this!
TextBox6.SetFocus
end if
Exit Sub
Err:
MsgBox Err.Description
End Sub

Excel VBA: Creating a confirmation prompt when a cell is edited

I am trying to create a confirmation so that when the cell is blank a prompt launches. If the user clicks confirm, the cell remains blank, else the cell returns to the original value. I have the following but it is not working, I hope that someone can solve this:
Private Sub MYtest()
Dim vatcell As Range
Set vatcell = Worksheets("Invoice").Range("D11:D11")
If vatcell = "" Then
response = MsgBox("Are you sure you want to change the VAT ammount?" & Chr(10) & Chr(10) _
& "Value = " & vatcell & Chr(10) & Chr(10) _
& "Do you really want to change it?", vbYesNo + vbQuestion, "Value Already Entered")
If response = vbYes Then
vatcell = ""
Else
vatcell = vatcell
End If
End If
End Sub
Thanks in advance.
The script from Daryll, which is not working:
There are two missing pieces to your solution. First, you need to store the value of the cell before it changed. Second, you need to connect to an event that tells you when the cell contents have changed.
' This is where you store the value before it was changed
Private last_vat As Variant
' this is where you capture the value when the worksheet is first loaded
Private Sub Worksheet_Activate()
Dim vatcell As Range
Set vatcell = Range("D11")
last_vat = vatcell.Value
End Sub
' This is where you respond to a change
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vatcell As Range
Set vatcell = Range("D11")
' Make sure the cell that changed is the one you are interested in
If Target = vatcell Then
' If it changed from something to nothing
If vatcell.Value = "" And last_vat <> "" Then
response = MsgBox("Are you sure you want to clear the VAT ammount?" & Chr(10) & Chr(10) _
& "Previous Value = " & last_vat & Chr(10) & Chr(10) _
& "Do you really want to change it?", vbYesNo + vbQuestion, "Value Already Entered")
If response = vbYes Then
' Allow the change (by doing nothing)
Else
' Reject the change
vatcell = last_vat
End If
End If
' Save changes from non-blank to different non-blank value
last_vat = vatcell.Value
End If
End Sub
I believe you want to have this be an event procedure. The below checks to see if cell D11 have been changed every time the worksheet "Invoice" is changed. Please note that this must be stored on the worksheet "Invoice" in the VBE.
Private Sub Worksheet_Change(ByVal Target as Range)
Dim vatcell As Range
Set vatcell = Worksheets("Invoice").Range("D11:D11")
If Not Intersect(Target,vatcell) is Nothing Then
response = MsgBox("Are you sure you want to change the VAT ammount?" & Chr(10) & Chr(10) _
& "Value = " & vatcell & Chr(10) & Chr(10) _
& "Do you really want to change it?", vbYesNo + vbQuestion, "Value Already Entered")
End If
If response = vbYes Then
vatcell = ""
Else
vatcell = vatcell
End If
End Sub

Resources