Convert formula to value once formula has calculated - excel

I'm using the following VBA module to create a Timestamp UDF, which stamps the date once the referenced cell reads "Done":
Function Timestamp(Reference As Range)
If Reference.Value = "Done" Then
Timestamp = Format(Date, "ddd dd mmm")
Else
Timestamp = ""
End If
End Function
The date stays the same even after refreshing / closing and opening the workbook as long as the referenced cell still reads "Done"; however if someone accidentally changes the referenced cell then the date is reset.
I need a VBA code to convert the formula to value once it has calculated, so the date will always stay the same. The solution needs to be automatic rather than manual and I can't enable iterative formulas on this workbook because it's used by multiple users. Any help much appreciated!

You can use the Worksheet Change event for that:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim AffectedCells As Range
Set AffectedCells = Intersect(Target, Me.Range("A:A")) ' Range A:A is the range we observe for 'done'
If AffectedCells Is Nothing Then Exit Sub
Dim Cell As Range
For Each Cell In AffectedCells
If Cell.Value = "done" Then
Dim UpdateTimestamp As Boolean
UpdateTimestamp = True
If Range("B" & Cell.Row).Value <> vbNullString Then
UpdateTimestamp = MsgBox("Timestamp exists do you want to update it?", vbQuestion + vbYesNo) = vbYes
End If
If UpdateTimestamp Then
Me.Range("B" & Cell.Row).Value = Format$(Date, "ddd dd mmm")
End If
End If
Next Cell
End Sub
// Edit according comment:
If you want to check multiple ranges for different things you need to slightly change your code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Cell As Range
Dim ObservedRangeA As Range
Set ObservedRangeA = Intersect(Target, Me.Range("A:A")) ' Range A:A is the range we observe for 'done'
If Not ObservedRangeA Is Nothing Then
For Each Cell In ObservedRangeA
If Cell.Value = "done" And Range("B" & Cell.Row).Value = vbNullString Then
Me.Range("B" & Cell.Row).Value = Format$(Date, "ddd dd mmm")
End If
Next Cell
End If
Dim ObservedRangeB As Range
Set ObservedRangeB = Intersect(Target, Me.Range("C:C")) ' Range C:C is the range we observe for ""
If Not ObservedRangeB Is Nothing Then
For Each Cell In ObservedRangeB
If Cell.Value = "" And Range("B" & Cell.Row).Value = vbNullString Then
Me.Range("B" & Cell.Row).Value = Format$(Date, "ddd dd mmm")
End If
Next Cell
End If
End Sub

Related

How do i get the Timestamp to update, when the cell contains a formula referencing another cell in another worksheet?

The following code is what gives me an initial timestamp (N) and updated time (O).
This works when the cell's in column D on WORKSHEET1 are manually updated.
The cell's in Column D WORKSHEET1 reference WORKSHEET2 Column E now. So for example D4 on WORKSHEET1 is ='WORKSHEET2'!E23.
When values are updated on WORKSHEET2, the D column on WORKSHEET1 updates automatically.
The timestamp code below then stops working and does not pick up this value change.
Can I insert a VBA code so that when i change the values on WORKSHEET2, and it updates on WORKSHEET1 because of the formula in cel D, the timestamp will work?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myTableRange As Range
Dim myDateTimeRage As Range
Dim myUpdatedRange As Range
Set myTableRange = Range("D1:D314")
If Intersect(Target, myTableRange) Is Nothing Then Exit Sub
Set myDateTimeRage = Range("N" & Target.Row)
Set myUpdatedRange = Range("O" & Target.Row)
If myDateTimeRage.Value = "" Then
myDateTimeRage.Value = Now
End If
myUpdatedRange.Value = Now
End Sub
Try this -
Private Sub Worksheet_Calculate()
Dim myTableRange As Range
Dim myDateTimeRage As Range
Dim myUpdatedRange As Range
Set myTableRange = Range("D1:D314")
For Each cell In myTableRange
Dim OldValue As Variant
Application.EnableEvents = False
Application.Undo
OldValue = cell.Value
Application.Undo
Application.EnableEvents = True
If OldValue <> cell.Value Then
Set myDateTimeRage = Range("N" & cell.Row)
Set myUpdatedRange = Range("O" & cell.Row)
If myDateTimeRage.Value = "" Then
myDateTimeRage.Value = Now
End If
myUpdatedRange.Value = Now
End If
Next cell

Same VBA code in the same worksheet for 2 different sets of table the first works, the second doesnt

I found the below code to input a timestamp automatically when one specific range has anything written and I wanted to do this in 2 specific places within the same worksheet, hence I wrote the same sequence, however the 1st works and the second doesnt, below my code:
Private Sub Worksheet_Change(ByVal Target As Range)
'==============logdate timestamp completed============
Dim myTableRange As Range
Dim myDayTimeRange As Range
'my Data Table Range
Set myTableRange = Range("E:E")
If Not Intersect(Target, myTableRange) Is Nothing Then
'Column for the date
Set myDateTimeRange = Range("A" & Target.Row)
If myDateTimeRange.Value = "" Then
myDateTimeRange.Value = Now
End If
End If
'==============logdate timestamp inflight============
Dim myTableRangeif As Range
Dim myDayTimeRangeif As Range
'my Data Table Range
Set myTableRangeif = Range("N19:R19")
If Not Intersect(Target, myTableRangeif) Is Nothing Then
'Column for the date
Set myDateTimeRangeif = Range("J" & Target.Row)
If myDateTimeRangeif.Value = "" Then
myDateTimeRangeif.Value = Now
End If
End If
End Sub
Just changed the code as suggested however the timestamp appears on the "A" column but not on the "J" one
When you change something in Range("N19:R19"), the Exit Sub is executed because it is true that Intersect(Target, myTableRange) Is Nothing.
You need to change the logic of Exiting the Sub if the Intersection is nothing.
If Not Intersect(Target, myTableRange) Is Nothing Then
'Column for the date
Set myDateTimeRange = Range("A" & Target.Row)
If myDateTimeRange.Value = "" Then
myDateTimeRange.Value = Now
End If
End If
...
If Not Intersect(Target, myTableRangeif) Is Nothing Then
'Column for the date
Set myDateTimeRangeif = Range("J" & Target.Row)
If myDateTimeRangeif.Value = "" Then
myDateTimeRangeif.Value = Now
End If
End If

Formatting Multiple cells with letters and number in VBA

I have been trying to figure this problem out for some time to no avail.
I have a file that tracks different types of invoices. The invoices have both numbers and letters ex. ABC_1234_12345678. I want excel to format the invoice codes by adding the under scores after the user inputs the invoice code(without the underscores). I currently have a code that can do it for single cell but I was wondering how I could change it format a select number of cells ex. A1-A8. I will add my code in the comments.
Thank you for the help, I will be very thankful. :)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngWatch As Range
Dim strOld As String
Dim strNew As String
'What cell is the invoice number in?
Set rngWatch = Range("A1")
'Did user change it?
If Intersect(rngWatch, Target) Is Nothing Then Exit Sub
strOld = rngWatch.Value
'Are there already hypens?
If Len(strOld) = Len(Replace(strOld, "_", "")) Then strNew = Left(strOld, 3) & "_" & Mid(strOld, 4, 3) & "_" & Mid(strOld, 8)
'Turn this off for the momenet
Application.EnableEvents = False
rngWatch.Value = strNew
Application.EnableEvents = True
End If
End Sub
Expand your rngWatch:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngWatch As Range, r As Range
Dim strOld As String
Dim strNew As String
'What cell is the invoice number in?
Set rngWatch = Range("A:A")
'Did user change it?
If Intersect(rngWatch, Target) Is Nothing Then Exit Sub
For Each r In Intersect(Target, rngWatch)
strOld = r.Value
'Are there already hypens?
If Len(strOld) = Len(Replace(strOld, "_", "")) Then
strNew = Left(strOld, 3) & "_" & Mid(strOld, 4, 3) & "_" & Mid(strOld, 8)
'Turn this off for the momenet
Application.EnableEvents = False
r.Value = strNew
Application.EnableEvents = True
End If
Next r
End Sub
Note:
We use a loop in case the user changes several cells in column A simultaneously via Copy/Paste.
This can depend upon how you want the code to run. You could for example create a macro that processes all of the cells within a specific range once it has been run, which to me is a sensible way to do it. You could get the macro to process only the selected cells, which is another option. There are many ways to do this.
I have taken your example code and adjusted it so that any adjustments to cells within the _MyNamedRange named range are processed. Just incase you enter the same code into more than 1 cell, it scans through the intersect using a for loop, but you may want to get rid of this depending on how you see your worksheet functioning. You will need to create a named range _MyNamedRange, where the macro will function.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngWatch As Range
Dim strOld As String
Dim strNew As String
Dim rngCell As Range, rngInter As Range
'What cell is the invoice number in?
Set rngWatch = Range("_MyNamedRange")
'Get intersect of the change
Set rngInter = Intersect(rngWatch, Target)
'Exit of the change does not intersect with the named range
If rngInter Is Nothing Then Exit Sub
'Scan through the intersect cells and adjust the cells
Application.EnableEvents = False
For Each rngCell In rngInter
strOld = rngCell.Value
'Are there already hypens?
strNew = ""
If Len(strOld) = Len(Replace(strOld, "_", "")) Then strNew = Left(strOld, 3) & "_" & Mid(strOld, 4, 3) & "_" & Mid(strOld, 8)
'Update the cell
rngCell.Value = strNew
Next rngCell
Application.EnableEvents = True
End Sub

Set two different ranges and execute code

I'd appreciate any help as I have no experience in vba.
What I'm trying to do
is that at the sheet "data" when the selected cell belongs to the rng1 then
the value for example 020318 at the cell changes to take the format 02/03/18.
At the same time in column ED at each cell there is a sum formula.
When this sum is under zero then a msgbox should pop up
for example
Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Dim rng1 As Range
Dim rng2 As Range
Dim cell As Range
Set rng1 = ThisWorkbook.Sheets("DATA").Range("I3:I1000,O3:O1000,P3:P1000,AE3:AE1000,AF3:AF1000,AH3:AH1000,AI3:AI1000")
Set rng2 = ThisWorkbook.Sheets("DATA").Range("ED3:ED1000")
If Not Intersect(ActiveCell, Range("I3:I1000,O3:O1000,P3:P1000,AE3:AE1000,AF3:AF1000,AH3:AH1000,AI3:AI1000")) Is Nothing Then
For Each cell In rng1
If cell <> "" Then
If Len(cell) = 6 Then
cell.Value = Format(cell.Value, "00/00/00")
End If
End If
Next cell
For Each cell In rng2
If IsNumeric(cell) = True Then
If cell.Value < 0 Then MsgBox "Τhe salary " & Cells(cell.Row, 2).Value & " before ....is " & Cells(cell.Row, 3).Value & " try more", vbCritical, "XXXXX"
End If
Next cell
End Sub
thanks in advance

timestamp once all cells are filled in

Here is the situation
Columns A through G are designed as drop down lists (data validation): Name, Number, ID, Phone, etc. Upon arrival to the office, each employee must fill their information into each cell of the row, in columns A to G.
What I want from a VBA code:
Only when each cell is filled in A:G, the date and time is stamped in the corresponding cell, in column H. It is permanent. It doesn't change ever. And once the date is stamped, the cells Columns A:G are locked as well.
My coding so far:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then
Target.Offset(0,1) = Now
End If
End Sub
This timestamp only works when cells in column A are changed :(
Should I be using a "case select" statement?
Is this what you are trying? (TRIED AND TESTED)
Option Explicit
'~~> Change this to the relevant password
Const MYPASSWORD As String = "BlahBlah"
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
On Error GoTo Whoa
Application.EnableEvents = False
Dim rng As Range
Dim nRow As Long
nRow = Target.Row
Set rng = Range("A" & nRow & ":G" & nRow)
'~~> Check if all cell from A-G are filled and
'~~> There is no time stamp already there
If Application.WorksheetFunction.CountA(rng) = 7 _
And Len(Trim(Range("H" & nRow).Value)) = 0 Then
ActiveSheet.Unprotect MYPASSWORD
Range("H" & nRow).Value = Now
Range("A" & nRow & ":H" & nRow).Locked = True
ActiveSheet.Protect MYPASSWORD
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub

Resources