I am using an Excel in which I need to get Auto user name and Time for two entry's example
1. If I insert a value in column 2 I need user name and time at cell "A" and "O"
2. In same Excel sheet again for the entry at Column(7) I need date and Username at cell "I" and "N"
My code working for single point and I am confuse how to use twice.
Check the code I try and advise
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim rng As Range, c As Range
Set rng = Application.Intersect(Target, Me.Columns(2))
If rng Is Nothing Then Exit Sub
For Each c In rng.Cells
If Len(c.Value) > 0 Then
If Len(c.Offset(0, -1).Value) = 0 Then
With c.EntireRow
.Cells(1, "A").Value = Now()
'.Cells(1, "B").Value = Date
.Cells(1, "O").Value = Environ("username")
End With
End If
End If
Set rng = Application.Intersect(Target, Me.Columns(7))
If rng Is Nothing Then Exit Sub
For Each c In rng.Cells
If Len(c.Value) > 0 Then
If Len(c.Offset(0, -1).Value) = 0 Then
With c.EntireRow
.Cells(1, "I").Value = Now()
'.Cells(1, "B").Value = Date
.Cells(1, "N").Value = Environ("username")
End With
End If
End If
Next c
End Sub
The problematic line is If rng Is Nothing Then Exit Sub because if Target is not in column 2 it exits sub and will never reach the second test for column 7.
So use If Not rng Is Nothing Then instead:
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim rng As Range, c As Range
Set rng = Application.Intersect(Target, Me.Columns(2))
If Not rng Is Nothing Then
For Each c In rng.Cells
If Len(c.Value) > 0 Then
If Len(c.Offset(0, -1).Value) = 0 Then
With c.EntireRow
.Cells(1, "A").Value = Now()
'.Cells(1, "B").Value = Date
.Cells(1, "O").Value = Environ("username")
End With
End If
End If
Next c
End If
Set rng = Application.Intersect(Target, Me.Columns(7))
If Not rng Is Nothing Then
For Each c In rng.Cells
If Len(c.Value) > 0 Then
If Len(c.Offset(0, -1).Value) = 0 Then
With c.EntireRow
.Cells(1, "I").Value = Now()
'.Cells(1, "B").Value = Date
.Cells(1, "N").Value = Environ("username")
End With
End If
End If
Next c
End If
End Sub
If I got it right, this is working for me:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
If Me.Cells(Target.Row, 1) = vbNullString Then Me.Cells(Target.Row, 1) = Now()
If Me.Cells(Target.Row, 15) = vbNullString Then Me.Cells(Target.Row, 15) = Environ("username")
ElseIf Target.Column = 7 Then
If Me.Cells(Target.Row, 9) = vbNullString Then Me.Cells(Target.Row, 9) = Now()
If Me.Cells(Target.Row, 14) = vbNullString Then Me.Cells(Target.Row, 14) = Environ("username")
End If
End Sub
Thought I'm not sure if you want the logging to be on the same row you are inserting data or rewrite it always on the same cell.
Related
I have error 438 message but cannot figure out why ? Do you have an idea ?
For each cells in my range B5:B28, I want to check string value and print a number accordingly to that string to the cell next to the right.
Public Sub RolloutStage()
Dim rng As Range
For Each rng In Worksheets("backEnd_Lost&Found").Range("B5:B28")
If Worksheets("backEnd_Lost&Found").rng.Value = "Live" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 8
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "Configuration" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 7
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "Testing" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 6
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "Planned" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 5
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "Pending" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 4
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "Not planned" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 3
ElseIf Worksheets("backEnd_Lost&Found").rng.Value = "No contact" Then
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 2
Else
Worksheets("backEnd_Lost&Found").rng.Value = "Not interested"
Worksheets("backEnd_Lost&Found").ActiveCell.Offset(0, 1).Value = 1
End If
Next
End Sub
Here is the correct version. Thank you
Public Sub RolloutStage()
Dim rng As Range
For Each rng In Worksheets("backEnd_Lost&Found").Range("B5:B28")
If rng.Value = "Live" Then
rng.Offset(0, 1).Value = 8
ElseIf rng.Value = "Configuration" Then
rng.Offset(0, 1).Value = 7
ElseIf rng.Value = "Testing" Then
rng.Offset(0, 1).Value = 6
ElseIf rng.Value = "Planned" Then
rng.Offset(0, 1).Value = 5
ElseIf rng.Value = "Pending" Then
rng.Offset(0, 1).Value = 4
ElseIf rng.Value = "Not planned" Then
rng.Offset(0, 1).Value = 3
ElseIf rng.Value = "No contact" Then
rng.Offset(0, 1).Value = 2
Else
rng.Value = "Not interested"
rng.Offset(0, 1).Value = 1
End If
Next
End Sub
Conditionally Populate Adjacent Cells
In your code...
You cannot use a variable as an object's property: instead of ws.rng.Value, use rng.Value.
A worksheet has no ActiveCell property: instead of ws.ActiveCell, use rng.
The For Each...Next Loop
What does the For Each cell In rg.Cells line do? You could think of it that in the first iteration, it writes the following invisible line right below:
Set cell = rg.Cells(1) ' B5
So in the continuation, you will use this cell to check the value and again use
this cell to write another value to the cell adjacent to the right.
In the next iteration, the invisible line looks like this:
Set cell = rg.Cells(2) ' B6
etc.
An Improvement
Public Sub RolloutStage()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Sheets("backEnd_Lost&Found")
Dim srg As Range: Set srg = ws.Range("B5:B28")
Dim sCell As Range, dCell As Range
For Each sCell In srg.Cells
Set dCell = sCell.Offset(, 1)
Select Case CStr(sCell.Value)
Case "Live": dCell.Value = 8
Case "Configuration": dCell.Value = 7
Case "Testing": dCell.Value = 6
Case "Planned": dCell.Value = 5
Case "Pending": dCell.Value = 4
Case "Not planned": dCell.Value = 3
Case "No contact": dCell.Value = 2
Case Else: sCell.Value = "Not interested": dCell.Value = 1
End Select
Next sCell
End Sub
I have a comboBox which list two columns (A and H). The conditions to list the items are:
1. Add items who doesn't content blank row from the column A
2. Add items who aren't equal to zero for the column H
I was able to perform the first condition with this code:
Private Sub UserForm_Activate()
Dim currentCell As Range
With ComboBox1
.ColumnCount = 2
.ColumnWidths = "70;30"
.ColumnHeads = False
.BoundColumn = 1
With Worksheets("Sheet")
With .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
For Each currentCell In .Cells
If Len(currentCell) > 0 Then
With Me.ComboBox1
.AddItem currentCell.Value
.List(.ListCount - 1, 1) = currentCell.Offset(, 7).Value
End With
End If
Next currentCell
End With
End With
End With
End Sub
I tried to change that part for the second condition, it doesn't work:
With Worksheets("Sheet")
With .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
For Each currentCell In .Cells
If Len(currentCell) > 0 & currentCell.Offset(, 7).Value <> 0 Then
With Me.ComboBox1
.AddItem currentCell.Value
.List(.ListCount - 1, 1) = currentCell.Offset(, 7).Value
Thank you
In your second condition, all you need to do is to replace the "&" with "And" to make it work. I would also avoid too many nested With's here. Maybe something like this:
Dim myRange As Range
Dim mySheet As Worksheet
Dim currentCell As Range
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
With Sheets("Sheet3")
Set myRange = Range(.Cells(2, 1), .Cells(lastRow, 1))
End With
With ComboBox1
.ColumnCount = 2
.ColumnWidths = "70;30"
.ColumnHeads = False
.BoundColumn = 1
For Each currentCell In myRange
If Len(currentCell) > 0 And currentCell.Offset(, 7).Value <> 0 Then
With Me.ComboBox1
.AddItem currentCell.Value
.List(.ListCount - 1, 1) = currentCell.Offset(, 7).Value
End With
End If
Next currentCell
End With
Private Sub UserForm_Initialize()
Dim Sh As Worksheet, rng As Range, arr(), cL As Range
Set Sh = ThisWorkbook.Worksheets("Sheet1")
'Make union of cells in Column A based on the two conditions given
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
If Sh.Range("A" & i).Value <> "" And Sh.Range("H" & i).Value <> 0 Then
If rng Is Nothing Then
Set rng = Sh.Range("A" & i)
Else
Set rng = Union(rng, Sh.Range("A" & i))
End If
End If
Next
'Make array of values of rng ang corresponding H Column cells
ReDim arr(rng.Cells.Count - 1, 1)
i = 0
For Each cL In rng
arr(i, 0) = cL.Value
arr(i, 1) = cL.Offset(0, 7).Value
Debug.Print rng.Cells(i + 1).Address; arr(i, 0); arr(i, 1)
i = i + 1
Next
'Assign the array to the ComboBox
ComboBox1.ColumnCount = 2
ComboBox1.List = arr
End Sub
I am trying to create a nonvolatile date stamp in Column A cells as entries are made in B, C and D cells in the same row.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
For i = 2 To 10000
If Cells(i, “B”).Value <> “” And _
Cells(i, “C”).Value <> “” And _
Cells(i, “D”).Value <> “” And _
Cells(i, “A”).Value = “” Then
Cells(i, "A").Value = Date & " " & Time
Cells(i, "A").NumberFormat = "m/d/yyyy h:mm AM/PM"
End If
Next
Range("A:A").EntireColumn.AutoFit
End Sub
I made it go to 10000 for the simple fact I do not know how to tell it to go as long as entries are entered.
It appears that you want to receive a datestamp once columns B:D are filled and column A is still empty.
If you write values back to the worksheet, disable event handling and provide error control.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("B:D"), Target) Is Nothing Then
On Error GoTo exit_handler
Application.EnableEvents = False
Dim r As Range
For Each r In Intersect(Range("B:D"), Target).Rows
If Cells(r.Row, "B").Value <> vbNullString And Cells(r.Row, "C").Value <> vbNullString And _
Cells(r.Row, "D").Value <> vbNullString And Cells(r.Row, "A").Value = vbNullString Then
Cells(i, "A").Value = Now
Cells(i, "A").NumberFormat = "mm/dd/yyyy h:mm AM/PM"
End If
Next t
End If
exit_handler:
Application.EnableEvents = True
End Sub
Try this to get rid of the loop:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
If Target.Count = 1 And Target.Column > 1 And Target.Column < 5 Then
If Cells(Target.Row, "B").Value <> "" And Cells(Target.Row, "C").Value <> "" And Cells(Target.Row, "D").Value <> "" And Cells(Target.Row, "A").Value = "" Then
Cells(Target.Row, 1).Value = Now
Cells(Target.Row, 1).NumberFormat = "m/d/yyyy h:mm AM/PM"
Range("A:A").EntireColumn.AutoFit
End If
End If
End Sub
In short, when you make a change on column B C or D, it will check if All 3 for that Row are filled and then put the time stamp if it doesnt have one. Skipping the loop. If you are pasting data instead of typing it, it will not work, instead use the loop from Pawel's answer.
I have created a macro to update certain values and after these values are entered they are used to create a text file for import into our system.
Below is a screen shot of the data entry screen:
Below is the code, I have written on the worksheet:
Option Explicit
Public Rec_Cnt As Integer
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Rng1 As Range
Dim Rng2 As Range
Dim Rng3 As Range
Dim Rng4 As Range
Rec_Cnt = Sheets("MD").Cells(3, 7)
Set Rng1 = Range("G2:G" & Rec_Cnt + 1)
Set Rng2 = Range("M2:M" & Rec_Cnt + 1)
Set Rng3 = Range("S2:S" & Rec_Cnt + 1)
Set Rng4 = Range("D2:E" & Rec_Cnt + 1)
If Not Application.Intersect(Target, Rng1) Is Nothing Then
If Len(Target) > 10 Then
Call Original_Ticket_Greater_Error
ElseIf Len(Target) < 10 Then
Call Original_Ticket_Lesser_Error
ElseIf Len(Target) = 10 Then
Cells(Target.Row, 8).Value = 9
Cells(Target.Row, 9).Value = "|"
Cells(Target.Row, 10).Value = "|"
Cells(Target.Row, 11).Value = "|"
Cells(Target.Row, 12).Value = "|"
Exit Sub
End If
ElseIf Not Application.Intersect(Target, Rng2) Is Nothing Then
If Len(Target) > 10 Then
Call Original_Cnj_Ticket_Greater_Error
ElseIf Len(Target) < 10 Then
Call Original_Cnj_Ticket_Lesser_Error
ElseIf Len(Target) = 10 Then
Cells(Target.Row, 14).Value = 9
Cells(Target.Row, 15).Value = "|"
Cells(Target.Row, 16).Value = "|"
Cells(Target.Row, 17).Value = "|"
Cells(Target.Row, 18).Value = "|"
Exit Sub
End If
ElseIf Not Application.Intersect(Target, Rng3) Is Nothing Then
If Len(Target) > 10 Then
Call Original_Ticket_Greater_Error
Exit Sub
ElseIf Len(Target) < 10 Then
Call Original_Ticket_Lesser_Error
Exit Sub
End If
ElseIf Not Application.Intersect(Target, Rng4) Is Nothing Then
If Cells(Target.Row, 3).Value = "Sales" Or Cells(Target.Row, 3).Value = "Sales Conjunction" Then
Cells(Target.Row, 6).Value = Application.Sum((Cells(Target.Row, 4).Value), (Cells(Target.Row, 5).Value))
Cells(Target.Row, 6).Value = Int(Cells(Target.Row, 6).Value * 100)
End If
End If
End Sub
Sub Original_Ticket_Greater_Error()
MsgBox "Original Ticket Number is more than 10 characters"
End Sub
Sub Original_Cnj_Ticket_Greater_Error()
MsgBox "Original Conj. Ticket Number is more than 10 characters"
End Sub
Sub Original_Ticket_Lesser_Error()
MsgBox "Original Ticket Number is less than 10 characters"
End Sub
Sub Original_Cnj_Ticket_Lesser_Error()
MsgBox "Original Conj. Ticket Number is less than 10 characters"
End Sub
Based on the code you can notice that I am updating certain cells only when the Target = 10 and otherwise not.
I wanted to change the font to RED when the Target is >10 or <10 and have tried couple of options but the font color doesn't change.
I have used Target.Font.Color and similar options.
Any help is much appreciated.
Thanks,
Sachin
You can achieve this with some conditional formatting.
From the Home ribbon click on Conditional Formatting and Manage Rules. Then select New Rule.
In the formula textbox, enter =INDIRECT("G"&ROW())<>10
In the applies to textbox, enter the column minus the header =$G$2:$G$1048576
Example Results:
I am trying to create a VBA code on a Excel sheet where I can automatically insert the created date (once data is being inserted in a row) and updated date (once any cell value of the row change from the previous value).
I tried the code below, I can get the created date but the not the update date.
I get this error
Type mismatch
on the line:
If Cells(Target.Row, i).Value <> PrevVal(Target.Row, i) Then
I guess the problem is that I don't know how to capture properly the previous value of a cell in order to compare it with the new value.
For reference: my table is like this:
Id Position1 Position2 DATE Created Date updated Data1 Data2 ....
Dim PrevVal As Variant
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo ExitGraceFully
If Selection.Rows.Count = 1 And Selection.Columns.Count = 1 Then
PrevVal = Selection.Value
Else
PrevVal = Selection
End If
ExitGraceFully:
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("B:B"), Target) Is Nothing Or Not
Intersect(Range("C:C"), Target) Is Nothing Then
Cells(Target.Row, 1).Value = Cells(Target.Row, 2) & Cells(Target.Row, 3)
If Cells(Target.Row, 4).Value = "" Then
Cells(Target.Row, 4).Value = Date & " " & Time
Cells(Target.Row, 4).NumberFormat = "m/d/yyyy h:mm AM/PM"
End If
End If
Dim i As Integer
If Target.Rows.Count = 1 And Target.Columns.Count = 1 Then
For i = 2 To 50
If Cells(Target.Row, i).Value <> PrevVal(Target.Row, i) Then
Cells(Target.Row, 5).Value = Date & " " & Time
Cells(Target.Row, 5).NumberFormat = "m/d/yyyy h:mm AM/PM"
End If
Next i
End If
End Sub
I finally corrected my code and now it's working well.
Dim PrevVal As Variant
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo ExitGraceFully
If Selection.Rows.Count = 1 And Selection.Columns.Count = 1 Then
PrevVal = Target.Value
Else
PrevVal = Target
End If
ExitGraceFully:
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("B:C"), Target) Is Nothing Then
Cells(Target.Row, 1).Value = Cells(Target.Row, 2) & Cells(Target.Row, 3)
If Cells(Target.Row, 4).Value = "" Then
Cells(Target.Row, 4).Value = Date & " " & Time
Cells(Target.Row, 4).NumberFormat = "m/d/yyyy h:mm AM/PM"
End If
End If
If Not Intersect(Range("F:Z"), Target) Is Nothing Then
Application.EnableEvents = False
If (PrevVal <> "") And (Cells(Target.Row, Target.Column).Value <> PrevVal) Then
Cells(Target.Row, 5).Value = Date & " " & Time
Cells(Target.Row, 5).NumberFormat = "m/d/yyyy h:mm AM/PM"
End If
End If
Application.EnableEvents = True
End Sub
Thank you so much #userZZZ, this is exactly what I was looking for!
I adapted your code to my requirements and added another constraint to change the date also when the content of a cell is deleted. I noticed that the code only works for single cells, but not for multiple cells. I might work on that sometime, but for now this is sufficient.
Edit: I added the possibility to manipulate multiple cells at once and update the date for all the corresponding rows. It still doesn't work for copy/paste of multiple cells though. For that purpose, I added an error message. Alternatively, the copy/paste mode can simply be deactivated by adding "Application.CutCopyMode = False" right at the beginning of the first function.
Dim PrevVal As Variant
Dim Block_rows As Integer
Dim Date_column As Integer
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo ExitGracefully
If Selection.Rows.Count = 1 And Selection.Columns.Count = 1 Then
PrevVal = Target.Value
Else
PrevVal = Target
End If
ExitGracefully:
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Date_column = 9
Block_rows = 8
On Error GoTo ErrorMessage
'Select and change single cell
If Not Intersect(Range("A:H"), Target) Is Nothing And Target.Row > Block_rows Then
Application.EnableEvents = False
If Selection.Rows.Count = 1 And Selection.Columns.Count = 1 Then
'Update date if value changes or is deleted
If (Cells(Target.Row, Target.Column).Value <> PrevVal) Or _
(Cells(Target.Row, Target.Column).Value = 0 And PrevVal <> 0) Then
Cells(Target.Row, Date_column).Value = Date
Cells(Target.Row, Date_column).NumberFormat = "dd-mmm-yyyy"
End If
'Select multiple cells, but only change single cells
ElseIf (Cells(Target.Row, Target.Column).Value <> PrevVal(Target.Row - Selection.Row + 1, Target.Column - Selection.Column + 1)) And _
(Cells(Target.Row, Target.Column).Value <> 0) Then
Cells(Target.Row, Date_column).Value = Date
Cells(Target.Row, Date_column).NumberFormat = "dd-mmm-yyyy"
'Delete multiple cells at once
Else
For RCount = 0 To Target.Rows.Count - 1
For CCount = 0 To Target.Columns.Count - 1
'Blank rows
If (Cells(Target.Row + RCount, Target.Column).Value = 0 And PrevVal(RCount + 1, CCount + 1) = 0) Then
'Delete cells or rows
ElseIf (Cells(Target.Row + RCount, Target.Column).Value = 0 And PrevVal(RCount + 1, CCount + 1) <> 0) Then
Cells(Target.Row + RCount, Date_column).Value = Date
Cells(Target.Row + RCount, Date_column).NumberFormat = "dd-mmm-yyyy"
End If
Next CCount
Next RCount
End If
End If
Application.EnableEvents = True
Exit Sub
ErrorMessage:
MsgBox ("This function is not supported for the automatic update of the date.")
Resume Next
End Sub