Change cell to clear content of other cells - vba

i want to clear the cells in column C D E if date change in column B
but only cells in same row where date is changed (Date =Sheet1!c2) so date is from sheet 1 but from different cells and different rows
Sample xls file
This is what i did but its not working until manually change date in Column B sheet 2:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("b1:b100")) Is Nothing Then
Cells(Target.Row, 3) = ""
Cells(Target.Row, 4) = ""
Cells(Target.Row, 5) = ""
End If
End Sub

Here is an extremely simple, limited, example. We are only monitoring cell B5 which contains a formula. The formula retrieves a date from another worksheet:
In the worksheet code area for this sheet we install the following Event macro:
Private Sub Worksheet_Calculate()
Dim Monitor As Range, Helper As Range
Dim rw As Long
Set Monitor = Range("B5")
Set Helper = Range("H5")
rw = Monitor.Row
Application.EnableEvents = False
If Helper.Value = "" Then
Helper.Value = Monitor.Value
Else
If Helper.Value <> Monitor.Value Then
Helper.Value = Monitor.Value
Range("C" & rw & ":E" & rw).ClearContents
End If
End If
Application.EnableEvents = True
End Sub
The code uses cell H5 as a "helper" The first time the code runs, the helper cell is filled. Each time after that, the code compares the "helper" against H5. If they become different, cells C thru E in that row are cleared.
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
EDIT#1:
Completely discard the original macro and install this one instead:
Private Sub Worksheet_Calculate()
Dim Monitor As Range, Helper As Range
Dim rw As Long, r As Range
Set Monitor = Range("B2:B100")
Set Helper = Range("H2:H100")
Application.EnableEvents = False
For Each r In Helper
If r.Value = "" Then
r.Value = r.Offset(0, -6).Value
End If
Next r
For Each r In Helper
If r.Value <> r.Offset(0, -6).Value Then
r.Value = r.Offset(0, -6).Value
rw = r.Row
Range("C" & rw & ":E" & rw).ClearContents
End If
Next r
Application.EnableEvents = True
End Sub
As you see, we must loop over each item in the ranges.

Try this using the Worksheet_Change Event (see https://msdn.microsoft.com/EN-US/library/office/dn301178.aspx)
Private Sub Worksheet_Change(ByVal Target As Range)
With Target
If .Column = 2 Then
Rem Disable Events. So it's not triggered by changes to columns D, E & F
Application.EnableEvents = 0
Rem Clear Columns D, E & F same row
.Cells.Offset(, 2).ClearContents
.Cells.Offset(, 3).ClearContents
.Cells.Offset(, 4).ClearContents
Rem Enable Events after changes
Application.EnableEvents = 1
End If: End With
End Sub

Related

Applying formula with changing row position to VBA

I have a worksheet that count the number of days between a designated date in column A and today() date in column B which stops the counting in column C if there is the word "CLOSED" in Column D. But I have a problem where I want to reapply back the formula if column D is blank again. I'm not sure how to make the column rows appear at the right place for the formula to be used
Below is the VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells = "CLOSED" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row) = Range("C" & Target.Row).Value
Range("B" & Target.Row) = Range("B" & Target.Row).Value
Application.EnableEvents = True
End If
End If
If Target.Cells = "" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
Range("B" & Target.Row).Value = "=Today()"
Application.EnableEvents = True
End If
End If
End Sub
I would really appreciate it if someone can teach me how to properly change the code:
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
as I am still new to VBA programming and would like to learn from my mistake
Below will do what you want. Learn that you can use the .FormulaR1C1 similar to effect of filling up/down. The potential issues including more than 1 cells is changed. Have not put checks if the cells in columns A/B are empty.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oRng As Range
Application.EnableEvents = False
For Each oRng In Target.Cells
With oRng
If .Column = 4 Then
If UCase(Trim(.Value)) = "CLOSED" Then
.Worksheet.Cells(.Row, "B").Value = .Worksheet.Cells(.Row, "B").Value
.Worksheet.Cells(.Row, "C").Value = .Worksheet.Cells(.Row, "C").Value
ElseIf Len(Trim(.Value)) = 0 Then
.Worksheet.Cells(.Row, "B").Formula = "=Today()"
.Worksheet.Cells(.Row, "C").FormulaR1C1 = "=TRUNC(RC[-2]-RC[-3])"
End If
End If
End With
Next oRng
Application.EnableEvents = True
End Sub
My understanding is that:
you need to act for any column 4 cell change, only
there can be more than one changed cell in column 4
so I'd go like follows (explanations in comments):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToProcess As Range
Set rangeToProcess = Intersect(Target, Columns(4)) 'mind edited cells in column 4 only
If rangeToProcess Is Nothing Then Exit Sub
Dim cell As Range
Application.EnableEvents = False
For Each cell In rangeToProcess 'loop through edited cells in column 4
With cell.Offset(, -2).Resize(, 2) ' reference a 2-cells range at the left of current cell
Select Case cell.Value 'process current cell value
Case "CLOSED" ' if it's "CLOSED" ...
.Value = .Value ' ... then leave values in referenced cells
Case "" ' if it's "" ...
.FormulaR1C1 = Array("=Today()", "=TRUNC(RC[-1]-RC[-2])") ' ... then restore formulas
End Select
End With
Next
Application.EnableEvents = True
End Sub

Locking specific cells in excel VBA

I have a macro I am working on currently.
Purpose
The objective in that once there is a value in column L , i need cells in the revelant row to lock. However this should not lock the whole worksheet, just the cells.
Code
Below is the code i have been been playing with. I am trying amend the code so to achieve my purpose above.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Row = 1 Then
If Target.Column = 3 Or Target.Column = 5 Then
Beep
Cells(Target.Row, Target.Column).Offset(0, 1).Select
End If
End If
End Sub
Example
The cells which will be locked are in yellow, if there is a date in column L
The reason why locking the whole worksheet wont overcome the problem is because any additional users will not be able to input there own data into the worksheet.
Merely locking the cells has no effect unless you protect the sheet. Firstly, unlock all the cells in the sheet, and then try this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 12 Or Target.Row = 1 Then Exit Sub
Range(Cells(Target.Row, 2), Cells(Target.Row, 11)).Locked = True
ActiveSheet.Protect
End Sub
Change the password in the first line of code with the actual password to unprotect the sheet.
Const PW As String = "123"
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge > 1 Then Exit Sub
Dim r As Long
If Target.Column = 12 And Target.Row > 1 Then
ActiveSheet.Unprotect Password:=PW
r = Target.Row
If Target <> "" Then
Range("B" & r & ":K" & r).Locked = True
Else
Range("B" & r & ":K" & r).Locked = False
End If
ActiveSheet.Protect Password:=PW
End If
End Sub

Vba macro if cell contains value, then input specific text on other cells

I have an excel document which has a lot of info and statistics and i am trying to figure out how to solve the following issue:
If a cell on column E, in the interval E5:E70, contains the "N/A" text (without quotes), i want to automatically input the "N/A" text on several specific cells in the same row
Added an image for reference.
Any help would be much appreciated, Thanks !
Latest edit:
I have attached a copy of the excel, maybe it will be a lot more helpful, for me it just won't work...it's so frustrating...
excel file
Paste the code below into the code sheet of the worksheet on which you want to have the action.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim C As Long
If Not Application.Intersect(Target, Range("E5:E70")) Is Nothing Then
SetApplication False
With Target
If StrComp(Trim(.Value), "N/A", vbTextCompare) = 0 Then
' recognises "n/a" as "N/A" and corrects entry
For C = Columns("E").Column To Columns("AL").Column
Cells(.Row, C).Value = "N/A"
Next C
End If
End With
SetApplication True
End If
End Sub
Private Sub SetApplication(ByVal AppMode As Boolean)
With Application
.EnableEvents = AppMode
.ScreenUpdating = AppMode
End With
End Sub
I assumed (based on the picture) that you want paste N/A's in this way: F - paste, G - don't paste, H - paste - and repeat this three further: paste, don't paste, paste, paste, don't paste, paste, etc.
So this code works accordingly to this rule. You just need to specify very last column instead of Column.Count - 2 - this bit says just that program should fill until the last column in a sheet.
Sub FillNAs()
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim i, j As Long
For i = 5 To 70
If UCase(Cells(i, 5).Value) = "N/A" Then
j = 6
Do While j < Columns.Count - 2
Cells(i, j).Value = "N/A"
Cells(i, j + 2).Value = "N/A"
j = j + 3
Loop
End If
Next i
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Try
Sub Demo()
Dim ws As Worksheet
Dim cel As Range
Set ws = ThisWorkbook.Sheets("Sheet1") 'change Sheet1 to your data sheet
For Each cel In ws.Range("E5:E70")
If CVErr(cel.Value) = CVErr(xlErrNA) Then
ws.Range("F" & cel.Row & ":I" & cel.Row) = CVErr(xlErrNA) 'mention desired range instead of (F:I)
End If
Next cel
End Sub

VBA code doesn't run when cell is changed by a formula or external link

I created an audit trail for any changes that occur on "Profile" sheet. Any changes that are made on the Profile sheet are recorded in another sheet - ChangeHistory.
However, I noticed that changes are only recorded when I change the contents of the cell manually. Changes that occur from external links from other sheets are not recorded.
Can you please help and suggest any amendments to this code? I am not an expert in VBA so would appreciated your valuable assistance.
This is my current code:
Profile code
Thanks in advance
Dim PreviousValue
Private Sub Worksheet_Change(ByVal Target As Range)
Dim AuditRecord As Range
' This is our change history ...
Set AuditRecord = Worksheets("ChangeHistory").Range("A4:B65000")
r = 0
' Now find the end of the Change History to start appending to ...
Do
r = r + 1
Loop Until IsEmpty(AuditRecord.Cells(r, 1))
' For each cell modified ...
For Each c In Target
Value = c.Value
Row = c.Row
' ... update Change History with value and time stamp of modification
AuditRecord.Cells(r, 1) = Worksheets("Profile").Cells(Row, 4)
AuditRecord.Cells(r, 2) = Value
AuditRecord.Cells(r, 3).Value = PreviousValue
AuditRecord.Cells(r, 5).NumberFormat = "dd mm yyyy hh:mm:ss"
AuditRecord.Cells(r, 5).Value = Now
AuditRecord.Cells(r, 4).Value = Application.UserName
r = r + 1
Next
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
PreviousValue = Target.Value
End Sub
There may be a better way to do this, but this is what came to my mind:
In Profile Sheet Module
Option Explicit
Public dArr As Variant
Private Sub Worksheet_Calculate()
Dim nArr As Variant
Dim auditRecord As Range
Dim i As Long
Dim j As Long
nArr = Me.UsedRange
'Look for changes to the used range
For i = 1 To UBound(dArr, 2)
For j = 1 To UBound(dArr, 1)
If nArr(j, i) <> dArr(j, i) Then
'write to range
If Not Write_Change(dArr(j, i), nArr(j, i), Me.Cells(j, i).Address) Then
MsgBox "The change was not recorded.", vbInformation
End If
End If
Next j
Next i
Erase nArr, dArr
dArr = Me.UsedRange
End Sub
Private Sub Worksheet_Change(ByVal target As Range)
Dim Cell As Range
Dim oldValue As Variant
For Each Cell In target
On Error Resume Next
oldValue = vbNullString
oldValue = dArr(Cell.Row, Cell.Column)
On Error GoTo 0
If oldValue <> Cell.Value Then
If Not Write_Change(oldValue, Cell.Value, Cell.Address) Then
MsgBox "The change was not recorded.", vbInformation
End If
End If
Next Cell
On Error Resume Next
Erase dArr
On Error GoTo 0
dArr = Me.UsedRange
End Sub
Private Sub Worksheet_SelectionChange(ByVal target As Range)
dArr = Me.UsedRange
End Sub
Public Function Write_Change(oldValue, newValue, cellAddress As String) As Boolean
Dim auditRecord As Range
On Error GoTo errHandler
Set auditRecord = Sheets("ChangeHistory").Range("A:A").Find("*", searchdirection:=xlPrevious).Offset(1, 0)
With auditRecord
.Value = cellAddress 'Address of change
.Offset(0, 1).Value = newValue 'new value
.Offset(0, 2).Value = oldValue 'previous value
.Offset(0, 3).NumberFormat = "dd mm yyyy hh:mm:ss"
.Offset(0, 3).Value = Now 'time of change
.Offset(0, 4).Value = Application.UserName 'user who made change
.Offset(0, 5).Value = Me.Range(Split(cellAddress, "$")(1) & 1).Value 'header column value
.Offset(0, 6).Value = Me.Range("D" & Split(cellAddress, "$")(2)).Value 'header row value
End With
Write_Change = True
Exit Function
errHandler:
Write_Change = False
Debug.Print "Error number: " & Err.Number
Debug.Print "Error descr: " & Err.Description
End Function
In ThisWorkbook Module
Private Sub Workbook_Open()
dArr = Sheets("Profile").UsedRange
End Sub
Explanation
The key to this solution is the public array dArr. The array will hold a static list of values from your sheet in memory and will update anytime you make a different selection on your worksheet using the SelectionChange event.
We use the Calculate event to handle times where formulas update cells' contents. To do this, we store the new values on the sheet in an array nArr and then loop through the array and compare the values against the static values in dArr.
Pasted values or manually added values will be captured using the Change event.
For this to work, dArr has to be filled anytime the workbook is opened by a user. To do this, you'll have to add this to the Workbook_Open event as shown above.
Other Notes
As noted here by Tim, there are times when global variables can lose their values by way of unhandled errors, so make sure to include good error handling in this project if you choose to use this solution.
This only writes value changes. Formatting changes will not be captured using this method.
Will not work if there's only one value on the Profile sheet. Could be modified to work like that if needed though.
I did some minor testing of the above code in 64-bit excel-2013, but you may want to do more extensive testing to ensure that all changes are captured via the above code.

VBA Excel - How to Automatically Fill a date in multi-columns if i filled column A

This is my first time to write a code and i try to write a code thats helps me to fill Columns B, C and D Automatically thats will happen when i fill Column A by myself.
this is the picture of that sheet i work on it now
Worksheet Explaining what i Want
The final result must be like this Picture
i try to google the code and i found a code but it not work at all
This is the first code
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
r.Offset(0, 1).Value = Date
Next r
Application.EnableEvents = True
End Sub
also i try to write another code thats may helps me to fill Column B and C based on above code results but still not work.
This is the code written by me
Private Sub Worksheet_Change1(ByVal Target As Range)
Dim i As Integer
For i = 6 To 1000
If Cells(i, "A").Value <> "" And Cells(i, "B").Value <> "" Then
Cells(i, "C").Value = Date
Cells(i, "C").NumberFormat = "mmm"
Cells(i, "D").Value = Date
Cells(i, "D").NumberFormat = "yyyy"
End If
Next
Range("C:C").EntireColumn.AutoFit
Range("D:D").EntireColumn.AutoFit
End Sub
anyone can help with that?
The Worksheet_Change event macro is triggered when one or more cells on the worksheet changes value. If you write values into the worksheet within the Worksheet_Change procedure (like you are with the dates) without first turning off event handling then another Worksheet_Change is triggered and the procedure tries to run on top of itself. Always turn off event handling with Application.EnableEvents = False before writing values to the worksheet.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:B")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Dim rw As Long, rng As Range
For Each rng In Intersect(Target, Range("A:B"))
If Application.CountA(Cells(rng.Row, "A").Resize(1, 2)) = 2 Then
Cells(rng.Row, "C").Resize(1, 2).Value = Date
Cells(rng.Row, "C").NumberFormat = "mmmm"
Cells(rng.Row, "D").NumberFormat = "yyyy"
End If
Next rng
Range("C:C").EntireColumn.AutoFit
Range("D:D").EntireColumn.AutoFit
End If
bm_Safe_Exit:
If CBool(Val(Err.Number)) Then _
Debug.Print Err.Number & ": " & Err.Description
Application.EnableEvents = True
End Sub
Remember to turn events back on with Application.EnableEvents = True before exiting the Worksheet_Change procedure or future value changes will not trigger the Worksheet_Change procedure again.
btw, the correct number format for October is mmmm, not mmm. The former gives the full month name; the latter only the three letter abbreviation (e.g. Oct).