Home » excel » excel – Calling Sub resulting in Sub undefined error

excel – Calling Sub resulting in Sub undefined error

Posted by: admin May 14, 2020 Leave a comment

Questions:

I’m trying to find a way to allow my tables to auto-expand while also preventing users from editing columns with formulas. Seems like it should be pretty straightforward without fancy coding given that it’s a pretty common situation, but I digress…

I’ve found the following code online (apologies to the author as I don’t remember where):

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

If Target.Cells.Count > 1 Then Exit Sub

    If Sheets("Instructions").Range("autoExpand") Like "Disabled" Then Exit Sub

    Dim Tbl As ListObject, Off As Integer, ExitCode As Label
    Dim TblFirstRow As Long, TblFirstColumn As Integer
    Dim FirstRowAllowed As Long

    On Error GoTo ExitCode

    Off = 0: If Target.Row > 1 Then Off = -1
    Set Tbl = ActiveSheet.ListObjects(1)
    TblFirstRow = Tbl.HeaderRowRange.Row
    TblFirstColumn = Tbl.HeaderRowRange.Cells(1, 1).Column
    OpenClipboard 0
    FirstRowAllowed = TblFirstRow

    If Target.Row >= FirstRowAllowed And Target.Row <= Tbl.ListRows.Count + TblFirstRow + 1 And _
        Target.Column <= Tbl.ListColumns.Count + TblFirstColumn And _
        Target.Cells.Offset(Off, 0).Locked = False Then
        Unprotect
        CloseClipboard
    Else
        GoTo ExitCode
    End If

    Exit Sub

    ExitCode:
        Protect DrawingObjects:=False, Contents:=True, Scenarios:= _
                False, UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
                AllowFormattingRows:=True, AllowInsertingRows:=True, AllowSorting:=True, _
                AllowFiltering:=True, AllowUsingPivotTables:=True
         CloseClipboard

End Sub

The code works great, but I’d like to use it on several worksheets within the same workbook, so I thought perhaps I could do:

IN WORKSHEET:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Call table_expand
End Sub

IN MODULE:

Sub table_expand()

(pasted code from within the Sub above)

End Sub

This, however, does not work – I’m getting a

“Sub not defined”

error. After some Googling it seems that the issue has to do with either missing or extra parentheses, but I’m not getting anything to work.

I can paste the code into all of the worksheets for the time being, but since I have about ten of them, basically I’m just trying to DRY it up a bit…

…which I should think is possible? As I’m sure is obvious I have almost zero experience with VBA, so many thanks for your help.

How to&Answers:

I’m guessing you are not passing the relevant Target to your regular macro. So it won’t know what to work on.

Something like this:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    myMacro Target
End Sub

And in the regular module:

Sub myMacro(Target As Range)
    MsgBox Target.Worksheet.Name & vbLf & Target.Address

End Sub

And in the regular macro, you’ll need to change your references to worksheets to Target.Sheet or something similar, if you reference the worksheet where the event took place.

Note that, in VBA, Call is not required.

Also, as I realized after reading the comment by @chrisneilsen, instead of putting your event code on each worksheet, you can use Workbook event code instead. Then you only need to enter it once. For example:

Workbook code:

Private Sub Workbook_SheetSelectionChange(ByVal sh As Object, ByVal Target As Range)
    Call myMacro(sh, Target)
End Sub

Regular Module:

Sub myMacro(sh As Worksheet, Target As Range)
    Dim Tbl As ListObject
    Set Tbl = sh.ListObjects(1)
    Stop

End Sub

Or you could just put all of your macro code into the workbook code; maintain a list of worksheets that you want this to occur on and add a test.

Private Sub Workbook_SheetSelectionChange(ByVal sh As Object, ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub

    If Sheets("Instructions").Range("autoExpand") Like "Disabled" Then Exit Sub

    Dim Tbl As ListObject, Off As Integer, ExitCode As Label
    Dim TblFirstRow As Long, TblFirstColumn As Integer
    Dim FirstRowAllowed As Long

    On Error GoTo ExitCode

    Off = 0: If Target.Row > 1 Then Off = -1
    Set Tbl = sh.ListObjects(1)
    TblFirstRow = Tbl.HeaderRowRange.Row
    TblFirstColumn = Tbl.HeaderRowRange.Cells(1, 1).Column
    OpenClipboard 0
    FirstRowAllowed = TblFirstRow

    If Target.Row >= FirstRowAllowed And Target.Row <= Tbl.ListRows.Count + TblFirstRow + 1 And _
        Target.Column <= Tbl.ListColumns.Count + TblFirstColumn And _
        Target.Cells.Offset(Off, 0).Locked = False Then
        Unprotect
       CloseClipboard
    Else
        GoTo ExitCode
    End If

    Exit Sub

ExitCode:
        Protect DrawingObjects:=False, Contents:=True, Scenarios:= _
                False, UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
                AllowFormattingRows:=True, AllowInsertingRows:=True, AllowSorting:=True, _
                AllowFiltering:=True, AllowUsingPivotTables:=True
         CloseClipboard
End Sub

Your code returns errors when run on my system, so I assume your environment is different since you wrote that it ran OK on your worksheet.

In particular:

  • OpenClipboard is not defined
  • CloseClipboard is not defined

and you will want to use the Worksheet.Protect method for that activity.