procedure too large vba for excel - vba

I am not used to writing code. I normally generate my code via macro and I am facing this issue. Can someone please help me?
Sub Test()
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Dim WorkRng1 As Range
Dim Rng1 As Range
Dim xOffsetColumn1 As Integer
Set WorkRng1 = Intersect(Application.ActiveSheet.Range("C8:C38"), Target)
xOffsetColumn1 = 18
If Not WorkRng1 Is Nothing Then
For Each Rng1 In WorkRng1
If Not VBA.IsEmpty(Rng1.Value) Then
Rng1.Offset(0, xOffsetColumn1).Value = Now
Rng1.Offset(0, xOffsetColumn1).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng1.Offset(0, xOffsetColumn1).ClearContents
End If
Next
Application.EnableEvents = True
End If
....................................
..............................
Dim WorkRng132 As Range
Dim Rng132 As Range
Dim xOffsetColumn132 As Integer
Set WorkRng132 = Intersect(Application.ActiveSheet.Range("EJ8:EJ38"), Target)
xOffsetColumn132 = 1
If Not WorkRng132 Is Nothing Then
For Each Rng132 In WorkRng132
If Not VBA.IsEmpty(Rng132.Value) Then
Rng132.Offset(0, xOffsetColumn132).Value = Now
Rng132.Offset(0, xOffsetColumn132).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng132.Offset(0, xOffsetColumn132).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub

One useful maxim in programming is Don't Repeat Yourself (DRY) - duplicated code is longer, harder to understand, and difficult to maintain.
There's a clear repeating pattern in your code. This block:
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Can be refactored into a re-usable method with two parameters:
Sub Test()
'....
ProcessRange Application.Intersect(Me.Range("B8:B38"), Target), 19
ProcessRange Application.Intersect(Me.Range("C8:C38"), Target), 18
'etc for the other ranges
'....
End sub
'subprocedure
Sub ProcessRange(WorkRng As Range, offsetCol as Long)
Dim Rng As Range
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
With Rng.Offset(0, offsetCol)
If Not VBA.IsEmpty(Rng.Value) Then
.Value = Now
.NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
.ClearContents
End If
End With
Next
Application.EnableEvents = True
End If
End Sub

Related

Worksheet_Change - 3 column multiplication evaluate to

I'm new to vba and frustrated.
I have the following code :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim VolRange As Range
Dim AffectVolRange As Range
Set VolRange = ActiveSheet.Range("AH:AK")
Set AffectVolRange = Intersect(Target, VolRange)
If Not AffectVolRange Is Nothing Then
Dim vRow As Variant
For Each vRow In AffectVolRange.Rows
With VolRange
Cells(vRow.Row, 37).Value = .Cells(vRow.Row, 34).Value * .Cells(vRow.Row, 35).Value *
.Cells(vRow.Row, 36).Value
End With
Next vRow
End If
End Sub
Initial value in columns 34,35,36, is null
You almos got it.
Take into account that your column indexes are relative to your new range, so 1, 2, 3, 4.
Also you need to disable the events with Application.EnableEvents = False to avoid recursive call to the function on the cells changed by the code event.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim VolRange As Range
Dim AffectVolRange As Range
Set VolRange = ActiveSheet.Range("AH:AK")
Set AffectVolRange = Intersect(Target, VolRange)
If Not AffectVolRange Is Nothing Then
Dim vRow As Variant
Application.EnableEvents = False
For Each vRow In AffectVolRange.Rows
With VolRange
.Cells(vRow.Row, 4).Value = .Cells(vRow.Row, 1).Value _
* .Cells(vRow.Row, 2).Value _
* .Cells(vRow.Row, 3).Value
End With
Next vRow
Application.EnableEvents = True
End If
End Sub

based on the split count I need to color the row with different color

Sub test()
Dim MyCell As Range, i As Long
Dim SelectedRange As Range
Set SelectedRange = Application.InputBox("Select Range", Type:=8)
Dim SplitRow As Long
SplitRow = Application.InputBox("Split Row Num", Type:=1)
Dim FormatRange As Long
FormatRange = SelectedRange.Rows.Count / SplitRow
Application.ScreenUpdating = False
For Each MyCell In SelectedRange
If i < FormatRange Then
MyCell.Interior.Color = vbRed
i = i + 1
Else
MyCell.Interior.Color = vbYellow
End If
Next MyCell
Application.ScreenUpdating = True
End Sub
Sub test()
Dim selectedRange As Range, splitRow As Long, formatRange As Long, i As Long
Set selectedRange = Application.InputBox("Select Range", Type:=8)
splitRow = Application.InputBox("Split Row Num", Type:=1)
Application.ScreenUpdating = False
With selectedRange
formatRange = .Rows.Count / splitRow
For i = 1 To .Rows.Count Step formatRange
.Cells(i, 1).Resize(formatRange, 1).Interior.ColorIndex = i / formatRange + 3
Next i
End With
Application.ScreenUpdating = True
End Sub

Excel VBA - Do not execute if

This is my Macro for a time stamp:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("N:N"), Target)
xOffsetColumn = 6
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm-dd-yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
I did not write this originally. I found it off of a forum as my macro knowledge is primitive at best.
Essentially I would like the time stamp to ONLY OCCUR ONCE so I need this macro not to run if a time stamp already exists in column AK.
I think this does what you want. It checks if AK is blank - if so, it adds the date, if not, it does nothing.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Long
Set WorkRng = Intersect(Application.ActiveSheet.Range("A:A"), Target)
xOffsetColumn = 36
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
If Len(Rng.Offset(0, xOffsetColumn)) = 0 Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm-dd-yyyy, hh:mm:ss"
End If
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub

Running a macro from a specific sheet in the same workbook

The macro that follows works alright if I put it in sheet1. However I would like to put this macro in sheet2. Unfortunately it doesn't make the job from sheet2, only from Sheet1. Can you please help me to make it run from Sheet2?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim sRes As Variant
On Error GoTo haveError
Set rng = Application.Intersect(Sheet1.Range("I15:I18"), Target)
If Not rng Is Nothing Then
If rng.Cells.count = 1 Then
sRes = Application.VLookup(rng.Value, _
Sheet2.Range("A56:B58"), 2, True)
'turn off events before updating the worksheet
Application.EnableEvents = False
rng.Offset(0, 1).Value = IIf(IsError(sRes), "???", sRes)
Select Case rng.Offset(0, 1).Value
Case "Low Risk": rng.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng.Offset(0, 2).Value = Date + 150
Case "High Risk": rng.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
End If
Exit Sub
haveError:
Application.EnableEvents = True '<< ensures events are reset
End Sub
The answer to this question it is simpler than I thought:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim rng1 As Range
Dim sRes As Variant
Dim sRes1 As Variant
On Error GoTo haveError
Set rng = Application.Intersect(Sheet1.Range("I15:I18"), Target)
Set rng1 = Application.Intersect(Sheet1.Range("I20:I23"), Target)
If Not rng Is Nothing Then
If rng.Cells.count = 1 Then
sRes = Application.VLookup(rng.Value, _
Sheet2.Range("A56:B58"), 2, True) 'Waterlow
'turn off events before updating the worksheet
Application.EnableEvents = False
rng.Offset(0, 1).Value = IIf(IsError(sRes), "???", sRes)
Select Case rng.Offset(0, 1).Value
Case "Low Risk": rng.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng.Offset(0, 2).Value = Date + 150
Case "High Risk": rng.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
ElseIf Not rng1 Is Nothing Then
If rng1.Cells.count = 1 Then
sRes1 = Application.VLookup(rng1.Value, _
Sheet3.Range("A28:B30"), 2, True) 'MUST
'turn off events before updating the worksheet
Application.EnableEvents = False
rng1.Offset(0, 1).Value = IIf(IsError(sRes1), "???", sRes1)
Select Case rng1.Offset(0, 1).Value
Case "Low Risk": rng1.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng1.Offset(0, 2).Value = Date + 150
Case "High Risk": rng1.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
End If
Exit Sub
haveError:
Application.EnableEvents = True '<< ensures events are reset
End Sub
It is only a matter to combine two procedures. A simple Elseif make it run (work :)) the macro.
Thanks to all of you for trying to help me.

Excel Worksheet_Change event triggering when deleting row

I have an excel worksheet with some vba code that when i change a specific cell it automatically sets the date of today into the cell next to it.
That all works good, but when i delete an entire row that's above that specific cell it changes the date automatically to the date of today.
This is the code i use to automatically the change the cell:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.Sheets("Example").Range("H10: H306, M10: M306, R10: R306, W10: W306, AB10: AB306, AG10: AG306"), Target)
xOffsetColumn = 1
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Sheets("Example").Unprotect
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "dd-mm-yyyy"
Sheets("Example").Protect
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
Is someone familiar with this problem?
You can do some tests on Range Target, to avoid executing the code
(with Goto or rather Exit Sub) :
Target.Cells.Count > 1
Target.Rows.Count > 1
Target.Columns.Count > 1
You can use theses tests at the start of the Sub or with If Not WorkRng Is Nothing Then
So your code could be :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
If Target.Columns.Count > 1 Then Exit Sub
Set WorkRng = Intersect(Application.Sheets("Example").Range("H10: H306, M10: M306, R10: R306, W10: W306, AB10: AB306, AG10: AG306"), Target)
xOffsetColumn = 1
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Sheets("Example").Unprotect
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "dd-mm-yyyy"
Sheets("Example").Protect
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub