Excel VBA Object Variable or With Block Variable Not Set Error

BeachDog_2600

New Member
Joined
Feb 4, 2025
Messages
11
Office Version
  1. 365
Platform
  1. Windows
Hello!

I'm trying to figure out where I'm going wrong with my code. Basically I want my code to decide what protections to initiate and how to proceed based on the data in column C on the 'LOA' tab. My table starts at A8 (headers) and is dynamic. My code should be allowing user entry from C9 to last row and only allowing users to edit columns A-B & H-O if there is data selected in Column C for that row. I had to adjust some of the ranges and that's where I started receiving the error. My original code allowed users to edit the headers because there was data in C8 so I tried to update the code to prevent that.

My current code is below:

VBA Code:
Private Sub Workbook_Open()
    Dim ws As Worksheet
    Dim wsRef As Worksheet
    Dim lastRow As Long
    Dim lastRowRef As Long
    
    ' Set worksheet references
    Set ws = ThisWorkbook.Sheets("LOA")
    Set wsRef = ThisWorkbook.Sheets("References")
    
    ' Unprotect workbook and sheets
    ThisWorkbook.Unprotect "123456"
    ws.Unprotect "123456"
    wsRef.Unprotect "123456"
    
    ' Sort data on LOA sheet
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    ws.Sort.SortFields.Clear
    ws.Sort.SortFields.Add Key:=ws.Range("C8:C" & lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ws.Sort
        .SetRange ws.Range("A8:O" & lastRow)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
    
    ' Set up data validation for Employee Name
    lastRowRef = wsRef.Cells(wsRef.Rows.Count, "A").End(xlUp).Row
    With ws.Range("C9:C" & lastRow).Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
        xlBetween, Formula1:="=References!$A$2:$A$" & lastRowRef
    End With
    
    ' Set formulas for columns D-G
    ws.Range("D9:D" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",2,FALSE)"
    ws.Range("E9:E" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",3,FALSE)"
    ws.Range("F9:F" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",4,FALSE)"
    ws.Range("G9:G" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",5,FALSE)"
    
    ' Find the last row with data in column C
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    
    ' Set the range for column C
    Set dataRange = ws.Range("C9:C" & lastRow)
    
    ' Loop through each cell in column C
    For Each cell In dataRange
        If Not IsEmpty(cell) Then
            ' Unlock corresponding cells in A, B, and H-O
            ws.Range("A" & cell.Row & ":B" & cell.Row).Locked = False
            ws.Range("H" & cell.Row & ":O" & cell.Row).Locked = False
        Else
            ' Lock corresponding cells in A, B, and H-O
            ws.Range("A" & cell.Row & ":B" & cell.Row).Locked = True
            ws.Range("H" & cell.Row & ":O" & cell.Row).Locked = True
        End If
    Next cell
    
    ws.Range("C9:C" & lastRow).Locked = False
    
    ' Protect LOA sheet
    ws.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    
    ' Protect References sheet
    wsRef.Protect "123456"
    
    ' Protect workbook
    ThisWorkbook.Protect "123456"
End Sub

Option Explicit

Private Const WARNING_MESSAGE As String = "Warning: You are attempting to {0} data." & vbNewLine & _
    "That is not allowed in this spreadsheet. Please press 'ESC' to return to your work."

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim ws As Worksheet
    Dim lastRow As Long
    On Error GoTo ErrorHandler
    
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    If Not Intersect(Target, Me.Range("C9:C" & lastRow)) Is Nothing Then
        Application.EnableEvents = False
        Me.Unprotect "123456"
        
        UpdateCellLockStatus Target
        
        Me.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    End If

ExitSub:
    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    MsgBox "An error occurred: " & Err.Description, vbCritical, "Error"
    Resume ExitSub
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        Select Case Application.CutCopyMode
            Case xlCut
                ShowWarningMessage "cut"
            Case xlCopy
                ShowWarningMessage "copy"
        End Select
    End If
End Sub

Private Sub UpdateCellLockStatus(ByVal Target As Range)
    Dim cell As Range
    Dim affectedRange As Range
    
    For Each cell In Intersect(Target, Me.Range("C9:C" & lastRow))
        Set affectedRange = Union(Me.Range("A" & cell.Row & ":B" & cell.Row), _
                                  Me.Range("H" & cell.Row & ":O" & cell.Row))
        
        affectedRange.Locked = (cell.Value = "")
    Next cell
End Sub

Private Sub ShowWarningMessage(ByVal action As String)
    MsgBox Replace(WARNING_MESSAGE, "{0}", action), vbExclamation + vbOKOnly, "Data Modification Warning"
End Sub

Private Sub Worksheet_Change_Paste(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        ShowWarningMessage "paste"
    End If
End Sub

Option Explicit

Sub AddNewRowToTable()
    
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim table_object_row As ListRow
    
    ' Set references to the worksheet and table
    Set ws = ThisWorkbook.Worksheets("LOA")  ' Replace "Sheet1" with your sheet name
    Set tbl = ws.ListObjects(1)  ' Replace "Table1" with your table name

    ' Unprotect workbook and sheets
    ws.Unprotect "123456"
    
    Set table_object_row = tbl.ListRows.Add
    table_object_row.Range(1, 1).Value = ""
    
    ' Protect LOA sheet
    ws.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
End Sub

My old code that worked is below:

VBA Code:
Private Sub Workbook_Open()
    Dim ws As Worksheet
    Dim wsRef As Worksheet
    Dim lastRow As Long
    Dim lastRowRef As Long
    
    ' Set worksheet references
    Set ws = ThisWorkbook.Sheets("LOA")
    Set wsRef = ThisWorkbook.Sheets("References")
    
    ' Unprotect workbook and sheets
    ThisWorkbook.Unprotect "123456"
    ws.Unprotect "123456"
    wsRef.Unprotect "123456"
    
    ' Sort data on LOA sheet
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    ws.Sort.SortFields.Clear
    ws.Sort.SortFields.Add Key:=ws.Range("C9:C" & lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ws.Sort
        .SetRange ws.Range("A9:AL" & lastRow)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
    
    ' Set up data validation for Employee Name
    lastRowRef = wsRef.Cells(wsRef.Rows.Count, "A").End(xlUp).Row
    With ws.Range("C9:C" & lastRow).Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
        xlBetween, Formula1:="=References!$A$2:$A$" & lastRowRef
    End With
    
    ' Set formulas for columns D-G
    ws.Range("D9:D" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",2,FALSE)"
    ws.Range("E9:E" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",3,FALSE)"
    ws.Range("F9:F" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",4,FALSE)"
    ws.Range("G9:G" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",5,FALSE)"
    
    ' Find the last row with data in column C
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    
    ' Set the range for column C
    Set dataRange = ws.Range("C1:C" & lastRow)
    
    ' Loop through each cell in column C
    For Each cell In dataRange
        If Not IsEmpty(cell) Then
            ' Unlock corresponding cells in A, B, and H-AL
            ws.Range("A" & cell.Row & ":B" & cell.Row).Locked = False
            ws.Range("H" & cell.Row & ":AL" & cell.Row).Locked = False
        Else
            ' Lock corresponding cells in A, B, and H-AL
            ws.Range("A" & cell.Row & ":B" & cell.Row).Locked = True
            ws.Range("H" & cell.Row & ":AL" & cell.Row).Locked = True
        End If
    Next cell
    
    ws.Range("C9:C" & lastRow).Locked = False
    
    ' Protect LOA sheet
    ws.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    
    ' Protect References sheet
    wsRef.Protect "123456"
    
    ' Protect workbook
    ThisWorkbook.Protect "123456"
End Sub

Option Explicit

Private Const WARNING_MESSAGE As String = "Warning: You are attempting to {0} data." & vbNewLine & _
    "That is not allowed in this spreadsheet. Please press 'ESC' to return to your work."

Private Sub Worksheet_Change(ByVal Target As Range)
    On Error GoTo ErrorHandler
    
    If Not Intersect(Target, Me.Range("C:C")) Is Nothing Then
        Application.EnableEvents = False
        Me.Unprotect "123456"
        
        UpdateCellLockStatus Target
        
        Me.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    End If

ExitSub:
    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    MsgBox "An error occurred: " & Err.Description, vbCritical, "Error"
    Resume ExitSub
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        Select Case Application.CutCopyMode
            Case xlCut
                ShowWarningMessage "cut"
            Case xlCopy
                ShowWarningMessage "copy"
        End Select
    End If
End Sub

Private Sub UpdateCellLockStatus(ByVal Target As Range)
    Dim cell As Range
    Dim affectedRange As Range
    
    For Each cell In Intersect(Target, Me.Range("C:C"))
        Set affectedRange = Union(Me.Range("A" & cell.Row & ":B" & cell.Row), _
                                  Me.Range("H" & cell.Row & ":AL" & cell.Row))
        
        affectedRange.Locked = (cell.Value = "")
    Next cell
End Sub

Private Sub ShowWarningMessage(ByVal action As String)
    MsgBox Replace(WARNING_MESSAGE, "{0}", action), vbExclamation + vbOKOnly, "Data Modification Warning"
End Sub

Private Sub Worksheet_Change_Paste(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        ShowWarningMessage "paste"
    End If
End Sub

Option Explicit

Sub AddNewRowToTable()
    
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim table_object_row As ListRow
    
    ' Set references to the worksheet and table
    Set ws = ThisWorkbook.Worksheets("LOA")  ' Replace "Sheet1" with your sheet name
    Set tbl = ws.ListObjects(1)  ' Replace "Table1" with your table name

    ' Unprotect workbook and sheets
    ws.Unprotect "123456"
    
    Set table_object_row = tbl.ListRows.Add
    table_object_row.Range(1, 1).Value = ""
    
    ' Protect LOA sheet
    ws.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
End Sub

I'm also trying to add code that will delete all of the data in a row (without removing data validations or formatting) when the data in Column C is deleted. I tried the following code, but I wasn't sure how to implement it.

VBA Code:
Option Explicit

Private Const WARNING_MESSAGE_DEL As String = "Warning: You are attempting to delete data in Column C." & vbNewLine & _
    "This action will clear the entire row. Do you want to proceed?"
    
Private Sub Worksheet_BeforeDelete(ByVal Target As Range, Cancel As Boolean)
    Dim intersectRange As Range
    
    ' Check if the deletion involves Column C
    Set intersectRange = Intersect(Target, Me.Columns("C"))
    
    If Not intersectRange Is Nothing Then
        If MsgBox(WARNING_MESSAGE_DEL, vbExclamation + vbYesNo, "Deletion Warning") = vbNo Then
            Cancel = True
        End If
    End If
End Sub

Private Sub ClearRowExceptColumnC(ByVal rowNumber As Long)
    ' Clear cells to the left of Column C
    Me.Range("A" & rowNumber & ":B" & rowNumber).ClearContents
    
    ' Clear cells to the right of Column C
    Me.Range("D" & rowNumber & ":" & Me.Cells(rowNumber, Columns.Count).Address).ClearContents
End Sub

I'm very much a novice when it comes to VBA, but I love the customizability and am trying to learn more. If you have any other advice it would be very much appreciated!
 
Update: I can raise the error in worksheet change event if I
- put a Stop statement near the top of the workbook open event code
- change the error handler to:
VBA Code:
ErrorHandler:
    MsgBox "An error occurred: " & Err.Description, vbCritical, "Error"
    'Resume ExitSub '<<<
    Resume
- save the wb and re-open
- then step through the code
For me, the error is raised because lastrow = 0, although the error doesn't seem to make sense for that reason.

I don't think posting code that works is going to help but I'll try to look at it after you reply to this suggestion. Add this blue line and see if it returns 0.
Rich (BB code):
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim ws As Worksheet
    Dim lastrow As Long
    On Error GoTo ErrorHandler
  
    lastrow = ws.Cells(ws.Rows.Count, "C").End(xlUp).row
    Msgbox lastrow
    If Not Intersect(Target, Me.Range("C9:C" & lastrow)) Is Nothing Then
then save and re-open your wb. BTW, you get the error when you open the wb or when doing something else?

I tried adding
VBA Code:
Msgbox lastrow
, but I never received a message box showing me what lastrow =.

As soon as I open the workbook, I receive the error 'An error occured: Object variable or With block variable not set' five times.

Now when I compile, I receive a 'Compile error: Variable not defined' for the following section (specifically 'lastRow').

VBA Code:
Private Sub UpdateCellLockStatus(ByVal Target As Range)
    Dim cell As Range
    Dim affectedRange As Range
   
    For Each cell In Intersect(Target, Me.Range("C9:C" & lastRow))
        Set affectedRange = Union(Me.Range("A" & cell.Row & ":B" & cell.Row), _
                                  Me.Range("H" & cell.Row & ":O" & cell.Row))
                                                           
        affectedRange.Locked = (cell.Value = "")
    Next cell
End Sub
 
Upvote 0
If it helps, here is a minisheet of my spreadsheet.

LOA Spreadsheet - Example.xlsm
O
15
LOA

I'm sorry, I don't know what went wrong there.

LOA Spreadsheet - Example.xlsm
ABCDEFGHIJKLMNO
9PendingSherryGiles,Rupert6Full-TimeBauer,JackB04Z006
10InactiveShaunJacobson,Zach4Full-TimePryce,WesleyB04Z004
11ActiveRodieJacobson,Zach4Full-TimePryce,WesleyB04Z004
12ActiveRodiePaulson,John3IntermittRosenberg,WillowB04Z003
13ActiveSherryPaulson,John3IntermittRosenberg,WillowB04Z003----Cont. & Int.-
14InactiveRodiePaulson,John3IntermittRosenberg,WillowB04Z003XX
15ActiveRodiePaulson,John3IntermittRosenberg,WillowB04Z003----
16InactiveShaunPaulson,John3IntermittRosenberg,WillowB04Z003
17InactiveLaurenSmith,Jack1Full-TimeGray,JeanB04Z001
18PendingLaurenSummer,Buffy5Full-TimeSpencer,ShawnB04Z005
19InactiveShaunSummer,Buffy5Full-TimeSpencer,ShawnB04Z005Cont. & Int.
20ActiveSherrySummer,Buffy5Full-TimeSpencer,ShawnB04Z005
21PendingShaunThomas,Bill2Part-TimeXavier,CharlesB04Z002XXRed. Schedule
22InactiveRodieThomas,Bill2Part-TimeXavier,CharlesB04Z002XXCont. & Int.
23InactiveRodieThomas,Bill2Part-TimeXavier,CharlesB04Z002X ---Continuous-
24#N/A#N/A#N/A#N/A
25#N/A#N/A#N/A#N/A
26#N/A#N/A#N/A#N/A
27#N/A#N/A#N/A#N/A
28#N/A#N/A#N/A#N/A
29#N/A#N/A#N/A#N/A
30#N/A#N/A#N/A#N/A
31#N/A#N/A#N/A#N/A
32#N/A#N/A#N/A#N/A
33#N/A#N/A#N/A#N/A
34#N/A#N/A#N/A#N/A
35#N/A#N/A#N/A#N/A
36#N/A#N/A#N/A#N/A
37#N/A#N/A#N/A#N/A
38#N/A#N/A#N/A#N/A
39#N/A#N/A#N/A#N/A
40#N/A#N/A#N/A#N/A
LOA
Cell Formulas
RangeFormula
D9:D40D9=VLOOKUP(C9,References!$A$2:$G$8,2,FALSE)
E9:E40E9=VLOOKUP(C9,References!$A$2:$G$8,3,FALSE)
F9:F40F9=VLOOKUP(C9,References!$A$2:$G$8,4,FALSE)
G9:G40G9=VLOOKUP(C9,References!$A$2:$G$8,5,FALSE)
Cells with Data Validation
CellAllowCriteria
F9:F40Any value
L9:L40List=References!$N$1:$N$5
M9:N40List=References!$M$1:$M$4
A9:A40List=References!$K$1:$K$3
B9:B40List=References!$L$1:$L$4
C9:C40List=References!$A$2:$A$8
D9:D40Any value


LOA Spreadsheet - Example.xlsm
ABCDEFGHIJKLMN
1Employee NameEmp IDEmployment ConditionReports ToDIDDivisionActiveLaurenContinuousMedical
2Smith,Jack00000001Full-TimeGray,JeanB04Z001PPDInactiveRodieIntermittentMilitary
3Thomas,Bill00000002Part-TimeXavier,CharlesB04Z002AMDDPendingShaunCont. & Int.Military - Paid
4Paulson,John00000003IntermittRosenberg,WillowB04Z003PPDSherryRed. SchedulePersonal
5Jacobson,Zach00000004Full-TimePryce,WesleyB04Z004HRDUncl. Service
6Summer,Buffy00000005Full-TimeSpencer,ShawnB04Z005PPD
7Giles,Rupert00000006Full-TimeBauer,JackB04Z006FFSD
8Samuelson,Sammy00000007IntermittBurr,BillB04Z007PPD
References
 
Upvote 0
, but I never received a message box showing me what lastrow
Then the fault lies elsewhere for you, which might mean my version is correct.
Now when I compile, I receive a 'Compile error: Variable not defined' for the following section (specifically 'lastRow').
Same thing as I said in post 5. If you use Option Explicit (IMO you should) then you must declare all variables. I also would not use words like "cell" because that is an Excel object and you're expecting the app to know exactly how "cell" is intended to be used. Got a tech coming in a few minutes so have to run now.
 
Upvote 0
Compile, fix, compile until there are no compile errors. That might solve your problem.

I think I figured out why I wasn't seeing errors when compiling. I went into Tools > Options > General > and selected 'Break on All Errors'. Now I am getting more errors when compiling.

I received a 'Run-time error '91': Object variable or With block variable not set' for the following piece of code (specifically 'lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row'). Would this be due to the use of 'Cells'? What should I be using in place of cell?

VBA Code:
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim ws As Worksheet
    Dim lastRow As Long
    On Error GoTo ErrorHandler
    
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    If Not Intersect(Target, Me.Range("C9:C" & lastRow)) Is Nothing Then
        Application.EnableEvents = False
        Me.Unprotect "123456"
        
        UpdateCellLockStatus Target
        
        Me.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    End If

ExitSub:
    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    MsgBox "An error occurred: " & Err.Description, vbCritical, "Error"
    Resume ExitSub
End Sub
 
Upvote 0
Now you're getting somewhere. If I was Excel, I'd say "OK, you said ws is a sheet, but you didn't tell me which one".
You need to Set object variables (to something); mostly when it is not related to the code module in some way. If the code is in Sheet9 and you want to refer to that sheet, you can use something like Me.Range("A1"). Or you can Set ws = Sheets("Sheet9") then say ws.Range("A1") = "test".
 
Upvote 0
I think I'm starting to understand. I went through and cleaned up my 'ThisWorkBook' code and it is working.

VBA Code:
Option Explicit

Private Sub Workbook_Open()
    ' Variables being used in this module
    Dim ws As Worksheet
    Dim wsRef As Worksheet
    Dim lastRow As Long
    Dim lastRowRef As Long
    Dim dataRange As Range
    Dim myCell As Range
    
    ' Set variable (Dim) definitions
    Set ws = ThisWorkbook.Sheets("LOA")
    Set wsRef = ThisWorkbook.Sheets("References")
    lastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
    lastRowRef = wsRef.Cells(wsRef.Rows.Count, "A").End(xlUp).Row
    Set dataRange = ws.Range("C9:C" & lastRow)
    
    ' Unprotect workbook and sheets
    ThisWorkbook.Unprotect "123456"
    ws.Unprotect "123456"
    wsRef.Unprotect "123456"
    
    ' Makes sure Column C remains unlocked so users can select Employee Name from dropdown
    ws.Range("C9:C" & lastRow).Locked = False
    
    ' Sort data on LOA worksheet by Employee Name (Column C)
    ws.Sort.SortFields.Clear
    ws.Sort.SortFields.Add Key:=ws.Range("C8:C" & lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ws.Sort
        .SetRange ws.Range("A8:O" & lastRow)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
    
    ' Set up data validation for Employee Name to pull from References worksheet
    With ws.Range("C9:C" & lastRow).Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
        xlBetween, Formula1:="=References!$A$2:$A$" & lastRowRef
    End With
    
    ' Set formulas for columns D-G to autofill from References worksheet
    ws.Range("D9:D" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",2,FALSE)"
    ws.Range("E9:E" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",3,FALSE)"
    ws.Range("F9:F" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",4,FALSE)"
    ws.Range("G9:G" & lastRow).Formula = "=VLOOKUP(C9,References!$A$2:$G$" & lastRowRef & ",5,FALSE)"
    
    ' Loop through each cell in column C checking if Employee Name is selected
    For Each myCell In dataRange
        If Not IsEmpty(myCell) Then
            ' Unlock corresponding cells in A, B, and H-O if Employee Name is present
            ws.Range("A" & myCell.Row & ":B" & myCell.Row).Locked = False
            ws.Range("H" & myCell.Row & ":O" & myCell.Row).Locked = False
        Else
            ' Lock corresponding cells in A, B, and H-O if Employee Name is not present
            ws.Range("A" & myCell.Row & ":B" & myCell.Row).Locked = True
            ws.Range("H" & myCell.Row & ":O" & myCell.Row).Locked = True
        End If
    Next myCell
    
    ' Protect LOA sheet
    ws.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    
    ' Protect References sheet
    wsRef.Protect "123456"
    
    ' Protect workbook
    ThisWorkbook.Protect "123456"
End Sub

I also tried to add a section on the worksheet module to prompt the user when they attempt to delete data in Column C (starting in C9 to lastrow), but I'm having a issue with the undo function. It deletes the row just fine when I select 'Yes', but when I select 'Cancel' it gives me 'Run-time error '1004': Method 'Undo' of object '_Application' failed'. Is there a different method I could use or am I using '.undo' incorrectly? The specific piece of code starts on line 24.

Code:
Option Explicit

Private Const WARNING_MESSAGE As String = "Warning: You are attempting to {0} data." & vbNewLine & _
    "That is not allowed in this spreadsheet. Please press 'ESC' to return to your work."

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim lastRow As Long
    Dim intersectRange As Range
    Dim YesNo As VbMsgBoxResult
    On Error GoTo ErrorHandler
    
    lastRow = Cells(Rows.Count, "C").End(xlUp).Row
    Set intersectRange = Intersect(Target, Me.Range("C9:C" & lastRow))
    
    If Not Intersect(Target, Me.Range("C9:C" & lastRow)) Is Nothing Then
        Application.EnableEvents = False
        Me.Unprotect "123456"
        
        UpdateCellLockStatus Target
        
        Me.Protect "123456", UserInterfaceOnly:=True, AllowFiltering:=True, AllowSorting:=True
    End If

    If Not intersectRange Is Nothing Then
        If IsEmpty(Target) Then ' Content was deleted
            YesNo = MsgBox("Warning: You are attempting to delete data in Column C." & vbNewLine & _
                           "This action will clear the entire row. Do you want to proceed?", vbOKCancel)
            If YesNo = vbOK Then ' If OK clicked
                With Application
                    .ScreenUpdating = False
                    .EnableEvents = False
                        Target.EntireRow.Delete ' Delete data in Column C
                    .ScreenUpdating = True
                    .EnableEvents = True
                End With
            ElseIf YesNo = vbCancel Then ' If Cancel clicked
                With Application
                    .EnableEvents = False
                        .Undo
                    .EnableEvents = True
                End With
            End If
        End If
    End If
    
ExitSub:
    Application.EnableEvents = True
    Exit Sub
    
ErrorHandler:
    MsgBox "An error occurred: " & Err.Description, vbCritical, "Error"
    Resume ExitSub

End Sub
    
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        Select Case Application.CutCopyMode
            Case xlCut
                ShowWarningMessage "cut"
            Case xlCopy
                ShowWarningMessage "copy"
        End Select
    End If
End Sub

Private Sub UpdateCellLockStatus(ByVal Target As Range)
    Dim myCell As Range
    Dim affectedRange As Range
    Dim lastRow As Long
    
    lastRow = Cells(Rows.Count, "C").End(xlUp).Row
    
    For Each myCell In Intersect(Target, Me.Range("C9:C" & lastRow))
        Set affectedRange = Union(Me.Range("A" & myCell.Row & ":B" & myCell.Row), _
                                  Me.Range("H" & myCell.Row & ":O" & myCell.Row))
        
        affectedRange.Locked = (myCell.Value = "")
    Next myCell
End Sub

Private Sub ShowWarningMessage(ByVal action As String)
    MsgBox Replace(WARNING_MESSAGE, "{0}", action), vbExclamation + vbOKOnly, "Data Modification Warning"
End Sub

Private Sub Worksheet_Change_Paste(ByVal Target As Range)
    If Not Application.CutCopyMode = False Then
        ShowWarningMessage "paste"
    End If
End Sub
 
Upvote 0
I'm not familiar with the application.undo method. When I looked it up on M$ the documentation indicates to me that it's a real thing. I think it's going to involve grabbing the value that it was before the change, then restoring it. You'd get the original value in the SelectionChange event (select a cell, populate a variant variable). This would get stored upon each selection so there's only ever one value. In your change event, you'd make the cell the original value if user clicks No or whatever should restore the value. The variable must be in the declarations section of the module, not of the code procedure.
 
Upvote 0

Forum statistics

Threads
1,226,848
Messages
6,193,318
Members
453,790
Latest member
yassinosnoo1

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