1

I have this function below which does the following:

  1. Takes two parameters (Header Name, Function Needed).
  2. The Header Name parameter is used to find the heading and subsequently to identify the range of that column up until the last row.
  3. The Function Needed parameter is used to switch in the select statement for any additional steps needed.
  4. At the end of most of the statements, I do a Range.Select then I exit my function with a selected range.

Here is the code:

Function find_Header(header As String, fType As String)
    Dim aCell As Range, rng As Range
    Dim col As Long, lRow As Long
    Dim colName As String

    With ActiveSheet
        Set aCell = .Range("B2:J2").Find(What:=header, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)

        'If Found
        If Not aCell Is Nothing Then
            col = aCell.Column
            colName = Split(.Cells(, col).Address, "$")(1)

            lRow = Range(colName & .Rows.count).End(xlUp).Row + 1

            Set myCol = Range(colName & "2")

            Select Case fType
                Case "Copy"
                    'This is your range
                    Set rng = Range(myCol.Address & ":" & colName & lRow).Offset(1, 0)

                    rng.Select
            End Select

        'If not found
        Else
            MsgBox "Column Not Found"
        End If
    End With

End Function

As I am trying to clean up my code, I have come across a section where I have specifically hard coded ranges and I am trying to make use of my function instead, however, I am now at a point where I am unable to make use of this function correctly as I cannot "pass" the range back to the sub and I cannot seem to make the selection the range object needed for the sub.

Here is what is in the sub:

Sub Copy_Failed()
    Dim xRg As Range, xCell As Range
    Dim i As Long, J As Long, count As Long
    Dim fType As String, colName As String
    Dim y As Workbook
    Dim ws1 As Worksheet, ws2 As Worksheet

    myarray = Array("Defect", "System", "Script")
    myEnv = Array("SIT", "UAT")
    myDefects = Array("New", "Existing")

    i = Worksheets("Run Results").UsedRange.Rows.count
    J = Worksheets("Failed").UsedRange.Rows.count

    Set y = Workbooks("Template.xlsm")

    Set ws1 = y.Sheets("Failed")
    Set ws2 = y.Sheets("Run Results")

    count = 3

    If J = 1 Then

        If Application.WorksheetFunction.CountA(ws1.UsedRange) = 0 Then J = 0

    End If

    ws2.Activate

    fType = "Copy"
    colName = "Status"

    Call find_Header(colName, fType)
End Sub

Before I used the function, the code looked like this:

lngLastRow = Cells(Rows.count, "B").End(xlUp).Row

Set xRg = ws2.Range("E3:E" & lngLastRow & i)

Now these 2 lines are performed in the function, so I don't need it in the sub. I have tried the following:

Set rngMyRange = Selection

Set rngMyRange = ActiveSheet.Range(Selection.Address)

Set xRg = ws2.Range(rngMyRange  & i)

But I get the error:

Type mismatch

So I am thinking this:

  1. Select the range in the function then use it in the sub - but how?
  2. Figure out how to pass the actual range object from my function to the sub

Although the second option would require some extra changes in my code, I would think this is the better option to go with.

GSerg
  • 76,472
  • 17
  • 159
  • 346
Eitel Dagnin
  • 959
  • 4
  • 24
  • 61
  • 2
    Functions should return something, a number, a range, a string etc. You are just selecting a cell and selecting is never good. Return a range object and then you can reference that in your other code. – SJR Feb 20 '19 at 09:54
  • @SJR Thank you for the reply. I have tried calling the function in the sub as above, then have the function look like this 'find_Header(header As String, fType As String) As Range' and then back in the sub I have the line look like this 'Set xRg = find_Header & i)' but I get the error "Arguments not Optional". – Eitel Dagnin Feb 20 '19 at 09:59
  • Function find_Header(header As String, fType As String) as Range and at the end of function add find_Header = rng – Jimmy M. Feb 20 '19 at 10:02

1 Answers1

2

Ok, so here is an illustration just so you can see what I mean. If you put "one" somewhere in B2:J2 it will select the range. I am only using Select here so that you can see the range it identifies. (Disclaimer: I don't fully understand what you are doing, and not sure you need all this code to achieve what you want.)

The Function now returns a range variable, and is assigned to r. Run the procedure x.

Sub x()

Dim r As Range

Set r = Range("a1", find_Header("one", "Copy"))
r.Select

End Sub

Function find_Header(header As String, fType As String) As Range

Dim aCell As Range, rng As Range
Dim col As Long, lRow As Long
Dim colName As String

With ActiveSheet
    Set aCell = .Range("B2:J2").Find(What:=header, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
    'If Found
    If Not aCell Is Nothing Then
        col = aCell.Column
        colName = Split(.Cells(, col).Address, "$")(1)
        lRow = Range(colName & .Rows.Count).End(xlUp).Row + 1
        Set myCol = Range(colName & "2")
        Select Case fType
            Case "Copy"
                'This is your range
                Set find_Header = Range(myCol.Address & ":" & colName & lRow).Offset(1, 0)
            End Select
    'If not found
    Else
        Set find_Header = Nothing
    End If

End With

End Function
SJR
  • 22,986
  • 6
  • 18
  • 26
  • Ahh, making progress!! :) So the issue I am facing now is that it is selecting the range starting in cell A1 up until the correct column's last cell. For example, I only need to use Column D, Cell D3:D30, but now I am getting A1:D30 – Eitel Dagnin Feb 20 '19 at 10:12
  • To add to this, the next line where this is used {Set xRg = ws2.Range(rngMyRange & i)} I get an error "Type Mismatch" – Eitel Dagnin Feb 20 '19 at 10:14
  • That's only because I specified A1 in this line `Set r = Range("a1", find_Header("one", "Copy"))`. Is D3:D30 the range returned by Find_Header? – SJR Feb 20 '19 at 10:14
  • Yes, in the function, the D3:D30 range is what is found/returned – Eitel Dagnin Feb 20 '19 at 10:15
  • 1
    OK so you can just refer directly to `find_Header("one", "Copy")` in your main procedure, e.g. `find_Header("one", "Copy").select`, because the function returns that range object. – SJR Feb 20 '19 at 10:17
  • Thank you so much, this is working great! :) I'm only still struggling on making it a range object as with this line {Set xRg = ws2.Range(rngMyRange & i)} where "i" is defined as Worksheets("Run Results").UsedRange.Rows.count – Eitel Dagnin Feb 20 '19 at 10:26
  • How is `rngMyRange` defined? – SJR Feb 20 '19 at 10:30
  • Damn, sorry. I completely spaced out. I was supposed to change it to this Set xRg = ws2.Range(Selection.Address & i). It is working now. Thank you kindly for your help! :) – Eitel Dagnin Feb 20 '19 at 10:33
  • OK, thanks for accepting the answer, but again would advise against using Selection. See https://stackoverflow.com/questions/10714251/how-to-avoid-using-select-in-excel-vba – SJR Feb 20 '19 at 10:37
  • 1
    Thank you. I will check it out :) – Eitel Dagnin Feb 20 '19 at 10:44