I see, there is always a way around these things. I added your sort line to the Worksheet_Change event and added an index column (which I have hidden) in column C of Sheet1. I have also made the only place the target range is defined to the Workbook_Open sub.
As I can't see what you have in column A - with your sort, you may need to add that back in, I have made it only sort by one column to make it work with the example. I can help with this if you see this as an option.
ThisWorkbook module:
Option Explicit Private Sub Workbook_Open() Dim endRow As Long Set tRng = Range("C5:E14") ' whole target range with index column With Sheets("UNDO") ' all code below that starts with a full stop (period in USA) will reference the UNDO sheet endRow = .Cells(Rows.Count, 1).End(xlUp).Row ' set end row of the UNDO sheet If endRow > 1 Then ' check if endRow is the header row, if it is then don't bother clearing the UNDO sheet .Range("A2:D" & endRow).ClearContents ' clear contents for every cell with data under the headings of the UNDO sheet End If End With End Sub
Sheet1 module:
Option Explicit Dim i As Long Private Sub Worksheet_Change(ByVal Target As Range) ' Code from: p45cal - www.vbaexpress.com - 03/12/2023 ' Edited by: georgiboy - www.vbaexpress.com - 06/12/2023 Dim rngToProcess As Range, sNewValue, sOldValue Dim rCell As Range, nr As Long Set rngToProcess = Intersect(Target, Application.Index(tRng, , 2)) ' create a range from cells edited If Not rngToProcess Is Nothing Then ' check if the above range is empty Application.EnableEvents = False ' switch off events so there is not an infinite loop sNewValue = Target.Value ' get the value that was just entered sOldValue = Target.Offset(, 1).Value ' get the previous value Application.UNDO ' undo your last entry Target.Offset(, 1).Value = Target.Value ' write the previous value to the cell to the right of target i = i + 1 ' increment the instance, used for the UNDO sub For Each rCell In rngToProcess ' loop through the cells in the target range With Sheets("UNDO") ' all code below that starts with a full stop (period in USA) will reference the UNDO sheet nr = .Cells(Rows.Count, 1).End(xlUp).Row + 1 ' get the next blank ro of the UNDO sheet .Range("A" & nr) = i ' write the instance number to the UNDO sheet .Range("B" & nr) = rCell.Offset(, -1) ' write the target index to the UNDO sheet .Range("C" & nr) = rCell.Offset(, 1).Value ' write what was the current value to the UNDO sheet .Range("D" & nr) = sOldValue ' write the existing previous value to the UNDO sheet End With Next rCell Target.Value = sNewValue ' write back the latest value you entered tRng.Sort tRng(1, 2), xlAscending, , , xlDescending ' sort the sort range Application.EnableEvents = True ' switch events back on End If End Sub
Module 1:
Option Explicit Public tRng As Range Sub UNDO() ' Code from: georgiboy - www.vbaexpress.com - 06/12/2023 Dim wsU As Worksheet, ws1 As Worksheet Dim x As Long, wsUend As Long, inst As Long Dim rCell As Range, indR As Long Application.EnableEvents = False ' switch off events so that the code below does not trigger the Worksheet_Change event Set wsU = Sheets("UNDO") ' the hidden sheet named UNDO Set ws1 = Sheets("Sheet1") ' the sheet that will be undone wsUend = wsU.Cells(Rows.Count, 1).End(xlUp).Row ' end row of sheet UNDO On Error GoTo JumpOut ' if the next line of code produces an error then it will go to JumpOut at the bottom of this sub inst = wsU.Range("A" & wsUend).Value ' latest instance that was added to the UNDO sheet On Error GoTo 0 ' switch error state back on For x = wsUend To 2 Step -1 ' loop backwards through the UNDO sheet If wsU.Range("A" & x) = inst Then ' check if the current row on UNDO sheet was the lates instance indR = Application.Index(tRng, , 1).Find(wsU.Range("B" & x).Value).Row ' find the index number on sheet1 Set rCell = ws1.Range("D" & indR) ' create a reference range to the cell on ws1 rCell.Value = wsU.Range("C" & x).Value ' write the previous value back to ws1 rCell.Offset(, 1) = wsU.Range("D" & x).Value ' write the previous previous value back to ws1 wsU.Range("A" & x & ":D" & x).ClearContents ' empty the row from the UNDO sheet, this allows you to have more undo's Else Exit For ' jump out as was not the last instance End If Next x Application.EnableEvents = True ' switch events back on Exit Sub JumpOut: Application.EnableEvents = True ' switch events back on MsgBox "Nothing to undo", vbInformation, "UNDO" End Sub




Reply With Quote