Automatic re-numbering of prioritized list VBA - vba

I have a list of priorities in Excel, for example:
4,
1,
3,
2
I want it to automatically update the priorities, if I enter a new name and assigns a priority. For example, if the new name has a priority of 2.
5,
1,
4,
3,
2
I have the following VBA code, which should do the job, but I can't get it to run.
Sub Worksheet_Change(ByVal Target As Range)
Dim rngPriorityList As Range
Dim lNewValue As Integer
Dim myCell As Range
If IsNumeric(Target.Value) Then 'Only run if the a number was entered
Set rngPriorityList = Intersect(Target, Range("I3:I500")) 'the named range for the task list
If Not Intersect(Target, rngPriorityList) Is Nothing Then 'Only run the following in the cell being updated was in the priority list range
If Target.Value >= 1 Then
For Each myCell In rngPriorityList.Cells 'Loop through the priority list range
If myCell.Value = Target.Value _
And myCell.Address <> Target.Address Then 'Finding cells with the same value, excluding the cell being changes
myCell.Value = myCell.Value + 1 'Increment the prioriry by 1
End If
Next myCell
End If
End If
End If
End Sub

a possible correction
wrong setting of rngprioritylist (should be Range("I3:I500" i.o. intersect( ...))
wrong test of mycell.value (should be >= i.o. =)
events should be disabled during the adaptation of the priorities as modifying the priorities will trigger the worksheet_change event.
Sub Worksheet_Change(ByVal Target As Range)
Dim rngPriorityList As Range
Dim lNewValue As Integer
Dim myCell As Range
If IsNumeric(Target.Value) Then 'Only run if the a number was entered
Set rngPriorityList = Range("I3:I500") 'the named range for the task list
If Not Intersect(Target, rngPriorityList) Is Nothing Then 'Only run the following in the cell being updated was in the priority list range
If Target.Value >= 1 Then
Application.EnableEvents = False
For Each myCell In rngPriorityList.Cells 'Loop through the priority list range
If myCell.Value >= Target.Value _
And myCell.Address <> Target.Address Then 'Finding cells with the same value, excluding the cell being changes
myCell.Value = myCell.Value + 1 'Increment the prioriry by 1
End If
Next myCell
Application.EnableEvents = True
End If
End If
End If
End Sub

Related

Excel VBA to insert duplicate row below based on drop down menu

I would like to add to the following VBA code, so that when "Did not attend" is selected from dropdown menu a duplicate row is ALSO inserted below the current row within the current worksheet "Details".
Private Sub Worksheet_Change1(ByVal Target As Range)
'Determine if change was made to a single cell in Column E
If Target.Column = 5 And Target.Cells.Count = 1 Then
'Determine if Did not attend was chosen
If Target = "Did not attend" Then
'If Yes...
''Disable Events
Application.EnableEvents = False
''Insert a row below
ActiveCell.Offset(1).EntireRow.Insert
''Copy, Paste
Rows(Target.Row).EntireRow.Copy _
Destination:=Sheets("Non Attendance").Range("A" & nxtRw)
''Re-enable Events
Application.EnableEvents = True
End If
End If
End Sub
This code should do what you want. Please try it.
Private Sub Worksheet_Change(ByVal Target As Range)
' 22 Jan 2018
Dim Rng As Range
Set Rng = Range(Cells(2, "E"), Cells(Rows.Count, "E").End(xlUp))
Debug.Print Target.Address
' Determine if change was made in Column E, below row 1 and above last row
If Not Application.Intersect(Target, Rng) Is Nothing Then
With Target
On Error Resume Next
If .Cells.Count = 1 Then ' if change was in a single cell
'Determine if Did not attend was chosen
If StrComp(.Value, "Did not attend", vbTextCompare) = 0 Then
' If Yes...
Application.EnableEvents = False
.Offset(1).EntireRow.Insert ' Insert a row below
With Worksheets("Non Attendance")
Set Rng = .Cells(.Rows.Count, "A").End(xlUp).Offset(1)
End With
' Copy, Paste
Rows(.Row).EntireRow.Copy Destination:=Rng
Application.EnableEvents = True
End If
End If
End With
End If
End Sub

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

Update cell, automatically copy row to a separate sheet

I have a worksheet comprising of two columns (A and B) ... the first of which is just a name, the second is a number.
If I make an edit to a number in column B, I want Excel to automatically copy that entire row to a second worksheet in order to create a list of edits that I have made.
The second worksheet would then be a continually updated list of changes that I have made to the first sheet, with the latest change (a copy of the two updated columns) added to the next unused row.
I hope that a bit of VBA trickery might be able to make this happen, but require some help to make it happen.
Try this in the sheet where you have data (under the Excel Objects), e.g Sheet1
Option Explicit
Dim PrevVal As Variant
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
Application.ScreenUpdating = False
Dim rng As Range
Dim copyVal As String
Set rng = Nothing
Set rng = Range("A" & Target.Row & ":B" & Target.Row)
'copy the values
With Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp)
.Offset(1, 0).Resize(1, rng.Cells.Count).Value = rng.Value
With Worksheets("Sheet1")
Range("A" & Target.Row).Copy
copyVal = CStr(PrevVal)
End With
.Offset(1, 0).PasteSpecial xlPasteFormats
.Offset(1, 1) = copyVal
Application.CutCopyMode = False
End With
End If
Application.ScreenUpdating = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Rows.Count > 1 Then Exit Sub
If Target.Columns.Count > 1 Then Exit Sub
PrevVal = Target.Value
End Sub
Here is some additional code to check the row number, as per the above answer and comments.
Dim row_num As Long
row_num = Cells(Rows.Count, "B").End(xlUp).Row
If row_num > 1 then row_num = row_num + 1 'Add 1 only when row number doesn't equal to 1, otherwise - 1.

Check values in a range before continuing

So right now I have an excel workbook for a task tracker. When the column that contains the completed date is filled in, it will take that row and copy it onto another sheet ("Complete") then delete it off the current sheet ("Current"). What I would like it to do before this is executed is check the values of columns H through M for either a "C" or "U". If any of the Cells in that range do not contain either or, then I want it to exit out and display a message. I am not to familiar with Excel or VBA, but decent with C++.
Here is the code as of right now:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim receivedDate As Range, nextOpen As Range, isect As Range
Set receivedDate = Sheet1.Range("G3:G166")
Set isect = Application.Intersect(Target, receivedDate)
If Not (isect Is Nothing) And IsDate(Target) = True Then
Set nextOpen = Sheet4.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Target.EntireRow.Copy Destination:=nextOpen.EntireRow
Target.EntireRow.Delete
End If
Application.EnableEvents = True
End Sub
Here is snip of what I have going on...
snip of work
Any help would be greatly appreciated. Sorry I tried looking around some.
Edit - more robust, added error handler and multi-cell update handling
Private Sub Worksheet_Change(ByVal Target As Range)
Dim receivedDate As Range, nextOpen As Range, isect As Range
Dim rngHM As Range, c As Range, rngDel As Range
Set receivedDate = Sheet1.Range("G3:G166")
'are any of the changed cells in the range we're monitoring?
Set isect = Application.Intersect(Target, receivedDate)
On Error GoTo haveError 'error handler ensures events get re-enabled...
'### remember that Target can contain >1 cell...
For Each c In isect.Cells
If IsDate(c.Value) Then
With c.EntireRow
Set rngHM = .Cells(1, "H").Resize(1, 6)
'EDIT: all cells must be C or U
If (Application.CountIf(rngHM, "C") + _
Application.CountIf(rngHM, "U")) <> rngHM.Cells.Count Then
MsgBox "No C or U on row " & c.Row & " !"
Else
Set nextOpen = Sheet4.Range("A" & Rows.Count) _
.End(xlUp).Offset(1, 0)
.Copy Destination:=nextOpen.EntireRow
'deleting rows while looping gives odd results,
' so store them up until done...
If rngDel Is Nothing Then
Set rngDel = c
Else
Set rngDel = Application.Union(rngDel, c)
End If
End If
End With 'entirerow
End If 'is date
Next c
'delete any copied rows in a single operation
If Not rngDel Is Nothing Then
Application.EnableEvents = False
rngDel.EntireRow.Delete
Application.EnableEvents = True
End If
Exit Sub
haveError:
'if your code errors out then this makes sure event handling gets reset
Application.EnableEvents = True
End Sub

Conditionally formatting ranges

I have two ranges of data that I want to compare with and format if they match. So I want to format a range 1 cell if any of that data matches to the the data in range 2. This is what I have so far - it works until I change the data to range 2 but doesn't update it:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim myRange As Range, cell As Range
Set myRange = Range("a9:a12")
For Each cell In myRange
If cell.Value = ActiveCell.Value And Not IsEmpty(ActiveCell.Value) Then
ActiveCell.Interior.ColorIndex = 3
End If
Next cell
End Sub
The problem is the cell still stays the colors that it was formatted from the first block of code so how can I change it back if the data in the second range gets changed?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myRange1 As Range
Set myRange1 = Range("f9:f12")
If Not Intersect(Target, Range("f1:f6")) Is Nothing Then
If Application.WorksheetFunction.CountIf(myRange1, ActiveCell.Value) > 0 _
Then ActiveCell.Interior.ColorIndex = 3 Else ActiveCell.Interior.Color = xlNone
End If
End Sub
Is this what you are trying?
If cell.Value = ActiveCell.Value And _
Not IsEmpty(ActiveCell.Value) Then
ActiveCell.Interior.ColorIndex = 3
Else
ActiveCell.Interior.Color = xlNone
End If
EDIT
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim myRange As Range
Set myRange = Range("a9:a12")
If Application.WorksheetFunction.CountIf(myRange, ActiveCell.Value) > 0 _
Then ActiveCell.Interior.ColorIndex = 3 Else ActiveCell.Interior.Color = xlNone
End Sub
EDIT
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myRange As Range
Set myRange = Range("f9:f12")
If Not Intersect(Target, myRange) Is Nothing Then
If Application.WorksheetFunction.CountIf(myRange, Target.Value) > 0 _
Then Target.Interior.ColorIndex = 3 Else Target.Interior.Color = xlNone
End If
End Sub
You seem to be taking a somewhat inefficient route with your loop and are ignoring one of the tools (e.g. Target) that is being provided to you.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'important for _SelectionChange event macros
'only process the cells to the extents of the data, not whole rows or columns
If Not Intersect(Target, Target.Parent.UsedRange) Is Nothing Then
Dim c As Range
For Each c In Intersect(Target, Target.Parent.UsedRange)
c.Interior.ColorIndex = 3 + _
4145 * IsError(Application.Match(c.Value2, Range("A9:A12"), 0))
Next c
End If
End Sub
For a Worksheet_SelectionChange event macro, the Target represents one or more cells that is the current Selection. By cycling through each of the cells in the current selection, you can perform this pseudo-Conditional Formatting on a larger range. The Target or Selection can be any number of cells up to the total number of cells in a worksheet but the ActiveCell property can only ever be a single cell.
I've reduced the color on/color off switch to a single worksheet MATCH function and a little maths. This does away with looping through the criteria cells.
Because you may want to select entire row(s) or column(s) at some point, I've included a cell processing 'limit' that will process to the extents of the data on the worksheet. Without a cap on the cells to process, it is very easy to get caught up in the unnecessary processing of entire rows or columns of blank cells when using Worksheet_SelectionChange.