Excel VBA - Issue with Worksheet_Change Code - vba

I'm trying to create a macro that puts the date in a cell on another worksheet, when the initial worksheet is changed, but it gives me an out of range error. Is there any way to get around this, or am I simply unable to use the Worksheet_Change for this case. If so, what can I use? I was simply trying to test it, so I only have this so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Worksheets("Sheet4").Activate
Range("E1").End(xlDown).Offset(1, 0).Value = Date
Application.EnableEvents = True
End Sub
I now have this:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Worksheets("Testing Sheet").Range("E2").Value = "" Then
Worksheets("Testing Sheet").Range("E2").Value = Date
Else
' Worksheets("Testing Sheet").Range("E2").End(xlDown).Offset(1, 0).Value = Date
End If
Application.EnableEvents = True
End Sub
But the statement at the Else is giving me an error saying Application defined or object defined error. (side note I don't have it commented out in my actual code)

You will get error because you are checking condition this
If Worksheets("Testing Sheet").Range("E2").Value = "" Then
For Suppose you have some value E2 Cell. So it goes to Else statement
Worksheets("Testing Sheet").Range("E2").End(xlDown).Offset(1, 0).Value = Date
But probably don't have data below E2 Cell. So .End(xlDown) Selects E1048576 Cell Which is the last allowed row supported by excel.
.Offset(1, 0).Value tries to point E1048577 Cell which is not supported.
So you get Application Defined Error. Hope this makes sense.

Related

Create date stamp when change detected

This script ends up being a runtime error when more than one cell in the target is modified.
I basically need to be able to make multiple changes at once and still have the date stamp work.
I'm still new to these sorts of scripts, any help will be appreciated.
Thanks.
Private Sub Worksheet_Change(ByVal Target As Range)
' Auto Date
Dim cell As Range
'Unprotecting Text Submission tool tab
wstextsubmissiontool.Unprotect "Abc123"
For Each cell In Target
If cell.Column = Range("E:E").Column Then
If cell.Value <> "" Then
Cells(cell.Row, "C").Value = Now
Else
Cells(cell.Row, "C").Value = ""
End If
End If
Next cell
'protecting Text Submission tool tab
wstextsubmissiontool.Protect "Abc123"
End Sub
The issue is that, by changing the cell that contains the time, you are changing the worksheet, so Excel wants to run your code to change the cell that contains the time... so basically the error is to prevent an infinite loop.
The way around it is to disable events at the start of your Worksheet_Change procedure with Application.EnableEvents = False. Just be sure to re-enable events at the End of the procedure (or also if you Exit the procedure early for some reason).
A simplified example (excluding your password protection) is:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Sheets("sheet1").Range("a1") = Now()
Application.EnableEvents = True
End Sub
More Info:
Microsoft : Application.EnableEvents property
Microsoft : Worksheet.Change event
Wikipedia : Infinite Loop
"Infinite Loop" 😜 (source)

Stop NOW() Function from Auto Updating

I have a cell which I want to record the time when adjacent cells to the left are changed. I do it with the NOW() function; however, the problem is that the time gets updated each time workbook is re-calculated. So, I am wondering whether there is any original way to prevent this very cell from auto-updating.
My current formula in the cell:
=IF(ISBLANK(H11),"",IF(H11="Interested",NOW(),IF(H11="Not Interested",NOW(),"")))
I personally have come up with this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Destination As Range
If Not Intersect(Target, Range("H:H")) Is Nothing Then
Target.Offset(0, 1).Value = Now
End If
End Sub
My issue with this code is that it is looking for any data in the cell. I am only wanting the cell to record the time when it contains either "Interested" or "Not Interested". The cell that I am looking at currently contains "In-progress". I have tried playing around with my code to try and incorporate these criteria's but I keep getting hit with errors. Any advice on what I can do to fix this? Thanks in advance.
Try the following code instead:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Destination As Range
If Not Intersect(Target, Range("H:H")) Is Nothing Then
If LCase(Trim(Target.Value2)) = "not interested" Or LCase(Trim(Target.Value)) = "interested" Then
Application.EnableEvents = False
Target.Offset(0, 1).Value = Now
Application.EnableEvents = True
End If
End If
End Sub
An alternative approach is a simple UDF that you use as =TimeChanged(H11)
Option Explicit
Option Compare Text
Public Function TimeChanged(theCell As Variant)
If TypeOf theCell Is Range Then theCell = theCell.Value2
If theCell = "Interested" Or theCell = "Not Interested" Then
TimeChanged = Now
Else
TimeChanged = ""
End If
End Function

Program excel to return a specific value

I have a spreadsheet that is going to be used in a survey.
How can I make the cells only to return "x" regardless of what the survey taker type in.
For instance, if I write a "w" in the cell, it should turn into an "x".
I have come to a point where I think there is an option when I protect the workbook or sheet. Because I can tell from another spreadsheet (which has this function) that it only works if the workbook is protected.
I tried to google it, but it seems as if I don't know the right keywords to find the answer.
Also, I have found a set of Vba code that I fiddle with, but I'm not sure this is correct. I don't want to attach the code as I don't want to confuse any response here.
Thank you for any help provided.
Put this code in the worksheet module and test it out, when you change a cell in column A (1) it will activate,
Where is the worksheet Module?
Copy and paste the code ,
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Intersect(Target, Range("A1,B1,C1,A4,B4,C4")) Is Nothing Then Exit Sub
Application.EnableEvents = 0
If Target <> "" Then Target = "X"
Application.EnableEvents = 1
End Sub
This should work for you (just change the range to the one you need) :
Option Explicit
Sub worksheet_Change(ByVal Target As Range)
On Error GoTo errorbutler 'error handler - important to have this in case your macro does a booboo
Application.Calculation = xlCalculationManual 'turn off automatic calculation to speed up the macro
Application.EnableEvents = False 'turn off events in order to prevent an endless loop
Dim LR, cell As Range 'Declare your variables
Set LR = Range("A1:b3") ' Select range of cells this macro would apply to
For Each cell In Target 'Loops through the cells that user have changed
If Union(cell, LR).Address = LR.Address Then 'Checks if the changed cell is part of your range
cell.Value="x" 'changes the value of that cell to x
End if
Next cell
Errorexit: 'part of error handling procedure
Application.EnableEvents = True 'Turn autocalc back on
Application.Calculation = xlCalculationAutomatic 'turn events back on
Exit Sub
Errorbutler: 'error handling procedure
Debug.Print Err.Number & vbNewLine & Err.Description
Resume Errorexit
End Sub
Oh yes, and this code should be put into the worksheet module - the same way as Dave has shown you

Exclude first row from macro

I have a macro that puts the current time into a cell upon editing any row. my problem is that this macro also executes for row 1 which are the titles. So it ends up changing the title of a column to a time.
The macro works fine but still changes the title. I tried the following:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If ActiveCell.Row = 1 Then Exit Sub
Cells(Target.Row, "I").Value = Now
Application.EnableEvents = True
End Sub
The ActiveCell can change to something else after you edit, so use the Target range rather than the ActiveCell. For example, if I hit {enter} to finish my edit, the ActiveCell is now on row 2 rather than 1.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
With Target
If .Row > 1 Then
Cells(.Row, "I").Value = Now
End If
End With
Application.EnableEvents = True
End Sub
I'm using With syntax to show the same Row you are comparing is the one you are editing. You could still put these on separate lines if you wish.
Also, user Jeeped makes a good point about the Application.EnableEvents = True line. It won't run if the row is 1, so they get turned off indefinitely. Better to test for > 1 and only run your update code on that condition.
If you turn off event handling, provide error control that makes sure that events will be re-enabled.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Safe_Exit
Application.EnableEvents = False
Dim r As Long, rw As Long, rng As Range, newTarget As Range
For Each rng In Target
If rng.Column <> 9 Then
If newTarget Is Nothing Then
Set newTarget = rng
Else
Set newTarget = Union(newTarget, rng)
End If
End If
Next rng
For r = 1 To newTarget.Rows.Count
rw = newTarget.Rows(r).Row
If rw > 1 Then _
Cells(rw, "I").Value = Now
Next r
Safe_Exit:
Application.EnableEvents = True
End Sub
If you are pasting or filling a large number of values then Target is all of the cells that changed. You need to guard against the top row while everything else receives the timestamp. When Target is more than a single cell, you only want to timestamp once per row.
And you don't want to turn off event handling then exit without turning it back on again.

excel vba on cell change error

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Range = Range("A1") Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
End Sub
that's the code however when i copy paste a set off cell, let's say 2 columns and 3 rows
it produce runtime error 13 type mismatch on line
If Target.Range = Range("A1") Then
why?
i simply wants the vba to do something everytime cell A1 changes
the value of A1 itself is an excel sum formula
You get type-missmatch error, becase you're trying to compare range (containing many cells) with single cell. If you want to do something every time cell A1 changed, use this one instead:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
On Error GoTo ErrHandler
If Not Intersect(Target, Range("A1")) Is Nothing Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
ExitHere:
Application.EnableEvents = True
Exit Sub
ErrHandler:
Resume ExitHere
End Sub
also note that I'm using Application.EnableEvents = False - it's a good habbit for Worksheet_Change event to use it. It prevents code from infinity firing itself each time you change any cell in event handler code.
UPD:
Btw, the value of A1 itself is an excel sum formula - you can't track changes of formula using above approach. I covered in details how you can do it in this question: Using Worksheet_Calculate event for tracking changes of formula
Simoco's answer should work for you. Another way (the one I usually use, though only out of habit) is to compare the addresses:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = Range("A1").Address Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
End Sub
You are getting an error because Target.Range is not defined. You should either just refer to Target (a Range Object) or Target.Address (the address of the Range Object). Secondly, depending on the context, Range("A1") refers to either the cell A1 itself (a Range Object) or the value in cell A1 (a literal value). You need to carefully think what you want to compare to what.
If, as you said, you want the comparison done whenever the value in Range("A1") changes then you should follow Simoco's suggestion.