Same Array/msgbox to display different messages

NatWally

New Member
Joined
Sep 19, 2018
Messages
26
Currently my array brings up three different msgboxes, as shown with the Functions 'Expired', 'Expiring', and 'NoTraining'. The array msgboxes display information based on whether a date is Expired (older than current date), Expiring (within 31 days), and is a date is missing (NoTraining).
No matter what, the msgboxes for the array will always come up, but will sometimes be blank (depending on the criteria in the SELECT CASE statement) and the following IF statement.
Does anyone know anyway of coding it so that if the msgboxes were to come up blank (if nothing fits the criteria), a different message will be shown in the box? I can't get the collection and boolean NoExpiredTraining to work properly bringing up an overall msgbox instead of the array msgboxes, so I need a message to appear in the Private Functions if there isn't going to be any data in the boxes (i.e. if the box would come up blank, then a "Everything okay" message)

This is my code:

Code:
[/FONT][/COLOR]
Sub Expire_New()


Dim arr()       As Variant
Dim msg(1 To 3) As String
Dim x           As Long
Dim nDx         As Long
Dim dDiff       As Long
LDays = 31


'I would recommend using a named sheet rather than
'ActiveSheet as this can change unexpectedly
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Support Staff")
With ws
    x = .Cells(.Rows.Count, TRAINING_DATE_COL).End(xlUp).Row
    arr = .Cells(21, 1).Resize(x - 20, 26).Value
End With


'I am a big fan of collections.  They make code easier to read
'and to implement.  The collection below will be scanned to
'see if there are any training dates that are set to expire within
'30 days or if there are people without any training
Dim colTrainingDate As Collection
Set colTrainingDate = CopyArrDimToCollection(arr, TRAINING_DATE_COL)


'This boolean will be used to control continued flow of the
'macro.  If NoExpiredTraining gets set to false, then there
'are people who must complete training.
'Dim NoExpiredTraining As Boolean: NoExpiredTraining = True


For x = LBound(arr, NAME_COL) To UBound(arr, NAME_COL)


    'Since every row requires a Name and Surname columns
    'to have data in them, let's check this first.
    'If a row doesn't have a name then skip it.
    If arr(x, NAME_COL) <> "" And arr(x, SURNAME_COL) <> "" Then


        'Always good practice to declare your variables/objects
        'relevant to where they will be used
        'vDx is an index used to loop through the collection of
        'Training Dates.  This is checking to see if any training
        'Dates are empty or less than 31 days from expiration
        Dim vDx As Variant
        For Each vDx In colTrainingDate
            If vDx = "" Then
                'blank date means needs training
                NoExpiredTraining = False
            ElseIf DateDiff("d", Date, vDx) < 31 Then
                'less than 31 days means needs training
                NoExpiredTraining = False
            End If
        Next


        'At this point you can determine if you want to continue
        'If there is no expired training, display the message and exit
        'the sub.
        If NoExpiredTraining Then
            'msg(4) = MsgBox("There are either no ...
            'is only used if want to do something based on
            'what button the user pressed.  Otherwise use
            'the Method form of MsgBox
            MsgBox "There are either no expired safeguarding certificates, or no certificate expiring within the next 31 days.", vbCritical, "Warning"
            Exit Sub
        Else
            'There is expired training.  Let's collect the status
            'of each individual
            If arr(x, TRAINING_DATE_COL) = "" Then
                'if the training date column is empty
                'put a really big default value in dDiff
                'otherwise you have to trap an error with DateDiff
                'and handle it
                dDiff = 100
            Else
                'training date column has a date value
                dDiff = DateDiff("d", Date, arr(x, TRAINING_DATE_COL))
            End If


            'Now let's see what the training status for the person is
            Select Case dDiff
                Case Is <= 0:   'Training is expired
                    msg(1) = Expired(msg(1), _
                          arr(x, NAME_COL), _
                          arr(x, 2), _
                          arr(x, TRAINING_DATE_COL))
                Case Is <= 31:  'Training is expiring
                    msg(2) = Expiring(msg(2), _
                          arr(x, NAME_COL), _
                          arr(x, 2), _
                          arr(x, TRAINING_DATE_COL), dDiff)
            End Select
            If Len(arr(x, 19)) = 0 And Len(arr(x, 1)) > 0 And Len(arr(x, 2)) > 0 Then
         msg(3) = NoTraining(msg(3), arr(x, 1), arr(x, 2), arr(x, 18))


  End If
  End If
  End If




 Next x
'Because of the Exit Sub statement above, the code bwlow
'will only execute if there are expired, expiring or missing
'training
For x = LBound(msg) To UBound(msg)
    msg(x) = Replace(msg(x), "@NL", vbCrLf)
    If Len(msg(x)) < 1024 Then
        MsgBox msg(x), vbExclamation, "Safeguarding Certificate Notification"
    Else
       MsgBox "String length for notification too long to fit into this MessageBox", vbExclamation, "Invalid String Length to Display"
    End If
Next x








Erase arr
Erase msg


End Sub


'***************************************************************************
'**
'** This fucntion copies all rows of data for the column specified into
'** a collection
Private Function CopyArrDimToCollection(ByRef mMultiDimArray() As Variant, _
                                    ByVal mColumnToCopy As Long) As Collection
Dim retVal As New Collection
Dim nDx As Long


For nDx = LBound(mMultiDimArray, 1) To UBound(mMultiDimArray, 1)
    retVal.Add mMultiDimArray(nDx, mColumnToCopy)
Next
Set CopyArrDimToCollection = retVal


End Function


Private Function Expired(ByRef msg As String, ByRef var1 As Variant, ByRef var2 As Variant, ByRef var3 As Variant) As String


If Len(msg) = 0 Then msg = "Persons with EXPIRED Safeguading Certificates@NL@NL"


Expired = msg & "(@var3) @var1 @var2@NL"
Expired = Replace(Expired, "@var1", var1)
Expired = Replace(Expired, "@var2", var2)
Expired = Replace(Expired, "@var3", var3)




End Function


Private Function Expiring(ByRef msg As String, ByRef var1 As Variant, ByRef var2 As Variant, ByRef var3 As Variant, ByRef d As Long) As String


If Len(msg) = 0 Then msg = "Persons with EXPIRING Safeguarding Certificates@NL@NL"


Expiring = msg & "(@var3) @var1 @var2 (@d days remaining)@NL"
Expiring = Replace(Expiring, "@var1", var1)
Expiring = Replace(Expiring, "@var2", var2)
Expiring = Replace(Expiring, "@var3", var3)
Expiring = Replace(Expiring, "@d", d)


End Function


Private Function NoTraining(ByRef msg As String, ByRef var1 As Variant, ByRef var2 As Variant, ByRef var3 As Variant) As String


If Len(msg) = 0 Then msg = "SAFEGUARDING TRAINING NOT COMPLETED FOR @NL@NL"


NoTraining = msg & " @var1 @var2@NL"
NoTraining = Replace(NoTraining, "@var1", var1)
NoTraining = Replace(NoTraining, "@var2", var2)
NoTraining = Replace(NoTraining, "@var3", var3)


End Function

 
Not sure what you're asking.
You mean if there is anything in the "On a temp visa" column, don't bother adding the person to the list regardless of the dates that might be there?
Or only if there is a Y or Yes?

OR only if there is a Y/YES?anything and there are no dates?
I don't know what accidentally adding a date means either, as the code adds dates if they're missing, yes? That's hardly an accident so maybe that's not what you mean.

I spent some time looking for a possible place to put such a test and came up with the notion of doing it here
Code:
 With VisaFind
    'Next two equations determine if the excel range has a null value
    'if so then the person training inquiry object's date field is set to a
    'default value of 1-1-1900 - this could be any valid date
    'otherwise the value is set to what is in the excel range from the sheet
    .VisaDate = IIf(mRow.Value2(1, 2) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 2))
    .VisaExpiryDate = IIf(mRow.Value2(1, 3) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 3))
    '.VisaLevel = mRow.Value2(1, 3)
    '.certSeenBy = mRow.Value2(1, 4)
        End With
by testing the value as in
If Not IsNull(mRow.Value2(1, 2)) Then...
. This would process a person if there is something in the column if that's what you want. Again, I'm not certain what criteria/parameters are.
 
Upvote 0

Excel Facts

Ambidextrous Undo
Undo last command with Ctrl+Z or Alt+Backspace. If you use the Undo icon in the QAT, open the drop-down arrow to undo up to 100 steps.
What I mean by it, is that with the previous one, the messages would only work if there was a name in A and B. If there was no name, then nothing would come up. All I need, along with there having to be a name in A and B, would be that there must also be a Y or YES inside the additional column.
 
Upvote 0
In order for the details to get added to the collection (dictionary) you want that there must be a value in both name columns, plus there must be a value in the "On a temp visa" column?
You gotta think a little bit about what you're asking for as believe it or not, it's somewhat specific and is not the same as what I just wrote. What if some enterprising user puts "X" or "maybe" or "?" in that column? That's not the same as "must be Y or YES" Shouldn't be too hard either way but my preference would be for me to make just one change for this.
 
Upvote 0
I have set up data validation (in normal Excel) so that either a "Y" or "YES", or "N" or "NO" has to be entered, and nothing else can be. And so if then a "Y" or "YES" is entered, then the code will find the ones that have the Y or YES, and will execute.

I hope that helps explain.

So if "Y" or "YES" is there, then I would need the code to find who those people are like before.
 
Upvote 0
I have set up data validation (in normal Excel) so that either a "Y" or "YES", or "N" or "NO" has to be entered
This does not appear to be true, at least not on my version of the Teaching Staff sheet. I can enter "y" or "dog" in the "On a temp Visa" column with no problem. Be that as it may, to achieve your latest request, you could change this
Code:
 With VisaFind
            'Next two equations determine if the excel range has a null value
            'if so then the person training inquiry object's date field is set to a
            'default value of 1-1-1900 - this could be any valid date
            'otherwise the value is set to what is in the excel range from the sheet
            .VisaDate = IIf(mRow.Value2(1, 2) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 2))
            .VisaExpiryDate = IIf(mRow.Value2(1, 3) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 3))
            '.VisaLevel = mRow.Value2(1, 3)
            '.certSeenBy = mRow.Value2(1, 4)
        End With
        'Update the object stored at the current key location
        'given by the value of nDx
        Set retVal(nDx) = VisaFind
        nDx = nDx + 1
     Next
to this
Code:
    If Not IsNull(VisaFind.firstName) And Not IsNull(VisaFind.surName) And (mRow.Value2(1, 1) = "Y" Or mRow.Value2(1, 1) = "Yes") Then
        
        With VisaFind
            'Next two equations determine if the excel range has a null value
            'if so then the person training inquiry object's date field is set to a
            'default value of 1-1-1900 - this could be any valid date
            'otherwise the value is set to what is in the excel range from the sheet
            .VisaDate = IIf(mRow.Value2(1, 2) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 2))
            .VisaExpiryDate = IIf(mRow.Value2(1, 3) = vbNullString, DateSerial(1900, 1, 1), mRow.Value2(1, 3))
            '.VisaLevel = mRow.Value2(1, 3)
            '.certSeenBy = mRow.Value2(1, 4)
        End With
        'Update the object stored at the current key location
        'given by the value of nDx
        Set retVal(nDx) = VisaFind
        nDx = nDx + 1
    End If
    
    Next
The expression test is also case sensitive, so "y" and "Y" is not the same. Therefore your validation must enforce upper case to be entered or change the case when the user moves off the cell (or some other intervention). You could also try adding Option Compare Text to your modules to see if the code will then accept "y" or "Y" as being the same.

In my testing with this, the textbox exceeds the 1024 limit based on the data supplied. If that's a problem resulting from this change, I'm afraid I have no other ideas. If it's normal, you might want to consider a userform with a textbox or some other suitable control to handle such situations.
Something like this might be of interest. Good luck!
 
Upvote 0
Thanks Micron for your help, I will take a look into it.

For the safeguarding ones, do you know if it is possible to get the array to write the results to a text file as well as display it in the msgbox as it does currently?
This way, the msgbox is a better view as it displays all the results on screen at one time, where the text file would then allow me to copy and paste that data from there - saves me having to individually type out each result displayed in the array (i.e. the names will be sent via email in a list).
 
Upvote 0
Google some key words to find out how to output to a file or simply output a list direct to an email. Access has the ability to output data as reports, pdf or other formats but I don't know about Excel. Your project is more suited to Access if you ask me, but that's a whole different ball game.
 
Upvote 0
Hi Micron,

So I currently have this below. It writes the results of this particular array into a txt file. However, no matter how many times you press the button, it doesn't replace the data in the txt file, only adds to it - this must be due to the 'Append'.
I have tried using 'Output' (which should always override the txt file), but it only ever writes the last line of the array into the txt file and nothing else. How do I get it to display all the results of the array, and then replace it every time the button is clicked?

Code:
Private Function Expired(ByRef msg As String, ByRef var1 As Variant, ByRef var2 As Variant, ByRef var3 As Variant) As String
Dim sFilePath As String
Dim FileNumber
If Len(msg) = 0 Then msg = "Persons with EXPIRED Safeguading Certificates:@NL@NL"
    Expired = msg & "@var1 @var2 (@var3)@NL"
    Expired = Replace(Expired, "@var1", var1)
    Expired = Replace(Expired, "@var2", var2)
    Expired = Replace(Expired, "@var3", var3)


sFilePath = "R:\HR and Admin\Expired.txt"
FileNumber = FreeFile
If (VBA.Len(VBA.Dir(sFilePath))) = 0 Then MsgBox "File Does not exist": End
Open sFilePath For Append As [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=FileNumber]#FileNumber[/URL] 
Print [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=FileNumber]#FileNumber[/URL] , var1, var2, var3
Close [URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=FileNumber]#FileNumber[/URL] 


End Function
 
Upvote 0
Open for output as #FileNumber then print to file. Pretty sure you won't get prompted to overwrite, nor will you have to test if the file exists first. Should work even if the file is open, but the changes won't appear in the opened file.
 
Upvote 0

Forum statistics

Threads
1,224,823
Messages
6,181,181
Members
453,022
Latest member
Mohamed Magdi Tawfiq Emam

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