Excel VBA - Run a macro when a cell is changed - vba

I am trying to write a macro that runs automatically any time a sheet is edited. Column H has the heading "Updated on" and the macro should put today's date in cell H# where # is the row of the cell that was changed. Here's the code I used:
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Select
Range("H" & ActiveCell.Row).Select
ActiveCell.Value = Date
End Sub
After saving the workbook and changing the value of cell A2, the code put today's date into H2 as I expected, but then gave me an error. I clicked debug, and the Target.Select line was highlighted. I assumed that looping was the problem, so I updated the code:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Target.Select
Range("H" & ActiveCell.Row).Select
ActiveCell.Value = Date
Application.EnableEvents = True
End Sub
This time, I changed the value of cell B3, and it put today's date into B4. Then Excel partially froze: I could still edit that workbook, but I couldn't open or view any other workbook. I closed all the workbooks, but then Excel itself would not close and I had to use the Task Manager to end it.

Using
Private Sub Worksheet_Change(ByVal Target As Range)
Range("H" & Target.Row).Value = Date
End Sub
will give you better stability. Target is the range that's changed.
It's just possible (I'm at home so can't check) that changing the value re-fires the Worksheet_Change event. If so, then block the recursion with
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address <> Range("H" & Target.Row).Address Then
Range("H" & Target.Row).Value = Date
End If
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
const DATE_COL as long = 8
Dim c as range
Set c = Target.Cells(1)
If c.Column = DATE_COL Then Exit Sub
On Error Goto haveError
Application.EnableEvents=False
Me.Cells(c.Row, DATE_COL).Value = Date
haveError:
Application.EnableEvents=True
End Sub

Related

VBA: How to automatically trigger macro without a button

I have made a macro that auto fill the formula on sheet1 whenever the row number of sheet2 is changed.
Is it possible to trigger it automatically without a button when i have any update on sheet2?
Sub Autofill()
Dim sg As Sheets
Dim Row As Long
Dim fillRow As Integer
Application.EnableEvents = False
Row = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
fillRow = Row - 1
Sheets("Sheet1").Select
Range("A1:E1").Select
Selection.Autofill Destination:=Range("A1:E" & fillRow), Type:=xlFillDefault
Application.EnableEvents = True
End Sub
You could try to create a sub like following:
Paste the following code. And change:
1) "D4" with your cells you want to "monitor"
2) Paste your macro in the line "Do things"
The problem is, your code is run everytime the focus is changed to another cell.
But you could also use Worksheet_BeforeDoubleclick if this is enough. Then every time you clicke twice the code will run
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Selection.Count = 1 Then
If Not Intersect(Target, Range("D4")) Is Nothing Then
'Do things
End If
End If
End Sub
Right-click on the sheet tab at the bottom of the scree, click 'view
code' then insert this following code in there.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Row As Long
Dim fillRow As Integer
This next line will exit the code if column A is not what is being
changed on the sheet. Delete it if you want the code to be triggered
by any change on any cell of the sheet.
if InRange(Target,Worksheets("Sheet2").range("A:A") = false then exit sub
Row = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
fillRow = Row - 1
Sheets("Sheet1").Select
Range("A1:E1").Select
Selection.Autofill Destination:=Range("A1:E" & fillRow), Type:=xlFillDefault
End Sub
Function InRange(Range1 As Range, Range2 As Range) As Boolean
InRange = Not (Application.Intersect(Range1, Range2) Is Nothing)
End Function
use a Worksheet.SelectionChange-Event.
in the Worksheet-VBA for sheet2 add:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Call Autofill()
End Sub
(This will be triggered if cell is changed, even if user does not leave the row, so check parameter Target.)

Vba code for Date today in data validation

I have a spreadsheet that has data validation in cells A2-A999 with the only option in the drop down menu being "Today" (without the quotation marks). I have a VBA code that changes the cell's value to today's date when "Today" is selected in the cell. However, this code has a problem. When I clear the contents of a group of cells, including the cell that has today's date in it, the spreadsheet thinks, then debugs and then closes; for example clearing A1 & B1 simultaneously.
However, if I clear A1 by itself, it clears the cell with no problems.
P.S. By " I clear", I meant to say: "I select the group of cells with the mouse and then hit the backspace button."
Can you guys help me fix the code so that I can clear many cells at the same time, including the cell with data validation.
The code that I am using is pasted in the worksheet section and is as the following:
Private Sub Worksheet_Change(ByVal Target As Range)
selectedVal = Target.Value
If Target.Column = 1 Then
selectedNum = Application.VLookup(selectedVal, Worksheets("DATA-
O").Range("DateToday"), 2, False)
If Not IsError(selectedNum) Then
Target.Value = selectedNum
End If
End If
End Sub
The answer to your problem is (as Dirk Reichel just mentioned in a comment) to loop through each of the affected cells:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Range
If Not Intersect(Columns(1), Target) Is Nothing Then
For Each c In Intersect(Columns(1), Target).Cells
selectedVal = c.Value
selectedNum = Application.VLookup(selectedVal, Worksheets("DATA-O").Range("DateToday"), 2, False)
If Not IsError(selectedNum) Then
Application.EnableEvents = False 'As recommended by K Paul
c.Value = selectedNum
Application.EnableEvents = True
End If
Next
End If
End Sub
However, based on what you say that the code is doing, I'm not sure why you don't just use:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Range
If Not Intersect(Columns(1), Target) Is Nothing Then
For Each c In Intersect(Columns(1), Target).Cells
If c.Value = "Today" Then
Application.EnableEvents = False 'As recommended by K Paul
c.Value = Date
Application.EnableEvents = True
End If
Next
End If
End Sub
If you want to be fast, there are 2 ways.
Use Evaluate to do it array-like:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Columns(1), Target) Is Nothing Then
With Intersect(Columns(1), Target)
If Evaluate("AND(" & .Address & "<>""Today"")") Then Exit Sub
.Value = Evaluate("IF(" & .Address & "=""Today"",TODAY()," & .Address & ")")
End With
End If
End Sub
or use Range.Replace which also can be very fast:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Columns(1), Target) Is Nothing Then
Intersect(Columns(1), Target).Replace "Today", Date, xlWhole, , True, , False, False
End If
End Sub
A small hint: hitting ctrl & ; will directly input todays date

VBA recognizing more than one cell is highlighted

I have the following VBA script:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.ScreenUpdating = False
If Not Application.Intersect(Target, Range("calendar")) Is Nothing Then
[selectedCell1] = ActiveCell.Value
Application.ScreenUpdating = True
End If
End Sub
Currently, It recognizes only one cell is highlighted and returns it into the specific cell named selectedCell1.
This is my example:
If I select the cell N25 which contains the date "03/08/2017" it returns "03/08/2017" into another sheet cell named "selectedCell1".
But what I would like it to do, is realize I've selected the entire week, and then return that entire week range in cell "selectedCell1". See:
And then return 01/08/2017 - 05/08/2017 (that entire range) in cell "selecetedCell1".
Not sure how to adjust this VBA script. Help would be appreciated. Thanks.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.ScreenUpdating = False
If Not Application.Intersect(Target, Range("calendar")) Is Nothing Then
If Target.Cells.Count = 1 Then
[selectedCell1] = Target.Value
Else
[selectedCell1] = Format(Application.WorksheetFunction.Min(Target), "dd/mm/yyyy") & " - " & Format(Application.WorksheetFunction.Max(Target), "dd/mm/yyyy")
End If
Application.ScreenUpdating = True
End Sub

Excel VBA: How to autocreate hyperlink from cell value?

I have a table called Table1
In Column B, I have the ticket number. e.g: 76537434
Requirement: when any change happens in any cell in column B, that cell (Target cell) to be changed into a hyperlink such that the hyperlink address would be example.com/id=76537434
Cell value i.e. 76537434 must remain the same
Add this event handler to your worksheet's code module:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 2 Then Exit Sub
Target.Hyperlinks.Delete ' or Target.ClearHyperlinks to conserve the formatting
Me.Hyperlinks.Add Target, "http://example.com/id=" & Target.value
End Sub
The following Worksheet_Change event should be able to solve your problem:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
Dim tmp As String
If Intersect(Range("B:B"), Target) Is Nothing Then Exit Sub
For Each cell In Target
If cell.Column = 2 Then
Application.EnableEvents = False
tmp = cell.Value2
cell.Parent.Hyperlinks.Add _
Anchor:=Cells(cell.Row, 2), _
Address:="http://example.com/id=" & tmp, _
TextToDisplay:=tmp
Application.EnableEvents = True
End If
Next cell
End Sub
Note, that you must copy it to the sheet and not into a separate module.
=HYPERLINK(E14&F14,"Name")
where cell E14 contains "http://www.example.com/id=" and cell F14 contains "76537434".
This soultions doesn't need VBA macros.

VBA define ranges and static date stamps

I need some help with this code as it doesn't work properly.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Cell As Range
For Each Cell In Target
With Cell
If .Column = Range("W:W").Column Then
Cells(.Row, "AC").Value = Int(Now)
End If
End With
Next Cell
End Sub
I am trying to get automatic static date stamps in column "AC" every time I fill in cells in column "W" and I want to start with row "19".
Tried to use
If .Column = Range("W19").End(xldown) Then
but it doesn't work.
I've just started using macro and vba and it will really help me if you can explain any solutions to me.
Thank you
Always turn off events if you are going to write to the worksheet in order that the Worksheet_Change event macro does not try to run on top of itself.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns("W:W")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Dim rng As Range
For Each rng In Intersect(Target, Columns("W:W"))
If rng.Row > 18 Then _
rng.Offset(0, 6) = Date 'or Now for datetime
Next rng
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
This should handle multiple changes to column W like a block range paste.