Have more than one Worksheet_Change in a Worksheet - vba

I am looking to limit my workbook users to 1000 characters over a range of cells (Example: A5:A30).
In other words limit the total characters in the range A5:A30 to 1000 characters.
When a user fills in a cell that sends the range over the 1000 character limit, it will call Application.undo which should just remove the last text that they added.
However since I have another Private Sub Worksheet_Change(ByVal Targe As Range) on the worksheet, it causes a bug.
Below is both Worksheet_Change subs. Both use the same cells.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim charCount As Long
If Not Intersect(Target, Range("E6,E11,E16")) Is Nothing Then
Dim arrValues As Variant
arrValues = Range("E6,E11,E16").Value2
Dim i As Long
Dim tempSplit As Variant
Dim j As Long
For i = LBound(arrValues) To UBound(arrValues)
tempSplit = Split(arrValues(i, 1), " ")
For j = LBound(tempSplit) To UBound(tempSplit)
charCount = charCount + Len(tempSplit(j))
Next j
Next i
End If
If charCount > 1000 Then
Application.Undo
MsgBox "Adding this exceeds the 1000 character limit"
End If
If Not Intersect(Target, Range("D6")) Is Nothing Then
If Target.Value2 = "Material" Then
'assumes the comment cell is one column to the right
Target.Offset(0, 1) = "**"
End If
End If
If Not Intersect(Target, Range("D7")) Is Nothing Then
If Target.Value2 = "Material" Then
'assumes the comment cell is one column to the right
Target.Offset(-1, 1) = "**"
End If
End If
If Not Intersect(Target, Range("D8")) Is Nothing Then
If Target.Value2 = "Material" Then
Target.Offset(-2, 1) = "**"
End If
End If
End Sub
Is there a way around this so I can have two Worksheet_Change on the same worksheet?

You cannot have two Worksheeet_Change events in one sheet. But, one is quite enough:
Private Sub Worksheet_Change(ByVal Target As Range)
Select Case True
Case Not Intersect(ActiveCell, Range("A5:A30")) Is Nothing
DoThingOne
Case Not Intersect(ActiveCell, Range("B5:B30")) Is Nothing
DoThingTwo
End Select
End Sub
Private Sub DoThingOne()
Debug.Print "THING ONE"
End Sub
Private Sub DoThingTwo()
Debug.Print "THING TWO"
End Sub

How about this revision using Vityata's idea?
Private Sub Worksheet_Change(ByVal Target As Range)
Select Case True
Case Not Intersect(Target, Range("E6,E11,E16")) Is Nothing
Dim charCount As Long
Dim arrValues As Variant
arrValues = Range("E6,E11,E16").Value2
Dim i As Long
Dim tempSplit As Variant
Dim j As Long
For i = LBound(arrValues) To UBound(arrValues)
tempSplit = Split(arrValues(i, 1), " ")
For j = LBound(tempSplit) To UBound(tempSplit)
charCount = charCount + Len(tempSplit(j))
Next j
Next i
If charCount > 1000 Then
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
MsgBox "Adding this exceeds the 1000 character limit"
End If
Case Not Intersect(Target, Range("D6")) Is Nothing
If Target.Value2 = "Material" Then
'assumes the comment cell is one column to the right
Target.Offset(0, 1) = "**"
End If
Case Not Intersect(Target, Range("D7")) Is Nothing
If Target.Value2 = "Material" Then
'assumes the comment cell is one column to the right
Target.Offset(-1, 1) = "**"
End If
Case Not Intersect(Target, Range("D8")) Is Nothing
If Target.Value2 = "Material" Then
Target.Offset(-2, 1) = "**"
End If
End Select
End Sub

Related

IF range doesn't return the value needed

I am facing one problem and I don't understand how it can be fixed. It is a simple code: if range("A1:A100") = "Product" then range("B1:B100") should have automatically 1 (this range is empty). So for example: If anyone writes in A1 = Product then B1 should automatically have 1. Else, if Product is deleted from A1, then 1 should be deleted from B1. My code is below:
Thanks in advance!
Sub product(o As Long)
If Cells(o, "A") = "Product" And Cells(o, "B") = "" Then
Cells(o, "B") = "1"
ElseIf Cells(o, "A") = "" And Cells(o, "B") = "1" Then
Cells(o, "B") = ""
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
Dim cell1 As Range
Set cell = Intersect(Range("b1:b100"), Target)
If Not cell Is Nothing Then
For Each cell1 In cell.Rows
product cell1.Row
Next cell1
End If
End Sub
In the worksheet's code sheet,
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Columns(1), Target) Is Nothing Then
On Error GoTo safe_exit
Application.EnableEvents = False
Dim trgt As Range
For Each trgt In Intersect(Columns(1), Target, Target.Parent.UsedRange)
Select Case LCase(trgt.Value2)
Case "product"
trgt.Offset(0, 1) = 1
Case ""
trgt.Offset(0, 1) = vbnullstring
Case Else
'do nothing
End Select
Next trgt
End If
safe_exit:
Application.EnableEvents = True
End Sub
Actually just a small fix is needed:
Set cell = Intersect(Range("A1:B100"), Target)
instead of b1:b100. You can even consider Range("A:B"), if you want to leave it active for the whole column.

Add text value to adjacent target range via Vlookup macro

Good afternoon, I would like by means of the changed cell value macro function
in Sheet1.Range ("I15:I18") to introduce a text value based on Vlookup function, avoiding using the formula. This is the table that Vlookup function text is looking at:
A B
1 0 Low Risk
2 10 Medium Risk
3 15 High Risk
It follows the code that it doesn't work for me:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim num As Long
Dim sRes As Variant
Set KeyCells = Sheet1.Range("I15:I18")
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
sRes = Application.VLookup(num, Sheet2.Range("A56:B58"), 2, True)
Debug.Print sRes
Sheet1.Target.Offset(0, 1).Text = sRes
End If
End Sub
The actual score that falls in the range is triggered by another macro that it works perfectly.
Here also follow the macro that works alright with a single cell:
Sub NumberVLookup()
Dim num As Long
num = 16
Dim sRes As Variant
sRes = Application.VLookup(num, Sheet2.Range("A56:B58"), 2, True)
Debug.Print sRes
Sheet2.Range("J15") = sRes
End Sub
I really appreciate your help in this regard.
Untested:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim sRes As Variant
on error goto haveError
Set rng = Application.Intersect(Me.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

Delete and shift cells up on a worksheet change

Note: One of the users asked this question and after I answered he delete it. I am just reposting the question and answer as in my opinion its a good example of bad coding habits and highlights why one needs to use Option Explicit
I have a worksheet change event where if Column I on sheet "current" is altered, it will then cut/paste that current row into the "completed" sheet. Only issue is that I need the empty row to delete from the sheet. My current code is only causing it to clear the row, and not delete/shift it up. How could I go about deleting a row and shifting up, without effecting the on change event?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim LastRowCompleted As Long
Dim RowToDelete As Long
RowToDelete = 0
LastRowCompleted = Sheets("completed").Cells(Sheets("completed").Rows.Count, "A").End(xlUp).Row
LastRowCompleted = LastRowCompleted + 1 'Next row after last row
Set KeyCells = Range("I:I")
Application.EnableEvents = False
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
'Cut and Paste Row
Target.EntireRow.Cut Sheets("completed").Range(LastRowCompleted & ":" & LastRowCompleted)
'Mark to delete row
RowToDelete = Target.EntireRow.Row
End If
Application.EnableEvents = True
Call DeleteRow(RowToDelete)
End Sub
Sub DeleteRow(Row As Long)
If RowsToDelete > 0 Then
Rows(Row).EntireRow.Delete Shift:=xlToUp
End If
End Sub
Always use Option Explicit
There is nothing called xlToUp correct enum value is xlUp
This is wrong
Sub DeleteRow(Row As Long)
If RowsToDelete > 0 Then
Rows(Row).EntireRow.Delete Shift:=xlToUp
End If
End Sub
There is no RowsToDelete variable so your condition always evaluates to false.
Correct code will be
Sub DeleteRow(RowsToDelete As Long)
If RowsToDelete > 0 Then
Rows(RowsToDelete).EntireRow.Delete Shift:=xlUp
End If
End Sub
Enable events after deleting the Row else you will get stuck in infinite loop.
Call DeleteRow(RowToDelete)
Application.EnableEvents = True
Always set CutCopyMode=False after cut or copy
This will work.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim LastRowCompleted As Long
Dim RowToDelete As Long
RowToDelete = 0
LastRowCompleted = Sheets("completed").Cells(Sheets("completed").Rows.Count, "A").End(xlUp).Row
LastRowCompleted = LastRowCompleted + 1 'Next row after last row
Set KeyCells = Range("I:I")
Application.EnableEvents = False
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
'Cut and Paste Row
Target.EntireRow.Cut Sheets("completed").Range(LastRowCompleted & ":" & LastRowCompleted)
Application.CutCopyMode = False
'Mark to delete row
RowToDelete = Target.EntireRow.Row
End If
Call DeleteRow(RowToDelete)
Application.EnableEvents = True
End Sub
Sub DeleteRow(RowsToDelete As Long)
If RowsToDelete > 0 Then
Rows(RowsToDelete).EntireRow.Delete Shift:=xlUp
End If
End Sub

Copy cell value to a range of cells

I'm new to VBA and I am trying to copy values from one cell to multiple cells when its value changes.
The value of A2 is constantly changing and when that happens I want that value to be copied to cells C2:C21 (and then eventually to cells D2:D21)
Here is an example of what I would like to achieve:
http://i.stack.imgur.com/xJZyZ.jpg
So far I wrote this code:
Sub Worksheet_Change(ByVal Target As Range)
For i = 0 To 19
If Not Intersect(Target, Range("AS2")) Is Nothing Then
Cells(Target.Row + i, 58).Value = Cells(Target.Row, 45).Value
End If
Next i
End Sub
but this only copies one single value of A2 to all the cells C2 to C22.
May anyone help me write this code properly?
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AS2")) Is Nothing Then
For CurCol = 3 to 4
For CurRow = 2 to 21
If Cells(CurRow, CurCol).Value = "" Then
Cells(CurRow, CurCol).Value = Target.Value
Exit Sub
EndIf
Next CurRow
Next CurCol
End If
End Sub
I guess this is what you're after:
Option Explicit
Sub Worksheet_Change(ByVal Target As Range)
Dim nVals As Long
If Not Intersect(Target, Range("A2")) Is Nothing Then
With Range("C2:D21")
nVals = WorksheetFunction.CountA(.Cells)
If nVals = .Count Then Exit Sub
Application.EnableEvents = False
On Error GoTo exitsub
.Cells(nVals Mod .Rows.Count + 1, IIf(nVals >= .Rows.Count, 2, 1)).Value = Target.Value
End With
End If
exitsub:
Application.EnableEvents = True
End Sub

How to prefix cell with 0, dependant on character length

Private Sub Worksheet_Change(ByVal Target As Range)
If Len(Target) = 8 Then
Exit Sub
End If
If Range("AF1:AF1000").Value = "Q" Then
Exit Sub
End If
On Error Resume Next
Application.EnableEvents = False
If Target.Column = 30 Then
lTarget = Len(Target)
Target.NumberFormat = "#"
For i = 1 To 8 - lTarget
Target.Value = "0" & Target.Value
Next
End If
Application.EnableEvents = True
End Sub
I'm trying to get this to basically when putting the information into a certain cell, if you put any less that 8 digits in, it will prefix it with '0 until it is 8 which is does, but now i want to adapt it so that it doesn't do it if a certain cell has the text "Q" in it, its not working when i do this how ever, little help?
EDIT: to make this easier the whole AF thing... its the entire AF column not just 1 to 1000 so how do i change that with what i have so far... probably need to re-write the whole thing..lol :(
If you mean it should check column AF on the same row for a Q, try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rCell As Range
If Not Intersect(Target, Me.Columns(30)) Is Nothing Then
On Error Resume Next
Application.EnableEvents = False
For Each rCell In Intersect(Target, Me.Columns(30)).Cells
Select Case Len(rCell.Value)
Case 0, 8
' ignore if 8 characters or blank
Case Else
If Strings.UCase$(Cells(rCell.Row, "AF").Value) <> "Q" Then
rCell.NumberFormat = "#"
rCell.Value = VBA.Right$("0000000" & rCell.Value, 8)
End If
End Select
Next rCell
End If
Application.EnableEvents = True
End Sub