Insert code in Excel workbook in "ThisWorkbook" using VBA - vba

I need help with inserting a sizeable code into "ThisWorkbook" module in Excel using VBA.
Using the code below I'm able to insert the code into "ThisWorkbook" module, but this method (as I've learned recently) has limitations of 24 lines due to line beak (& _).
Sub AddCode()
Dim VBP As Object
Dim newmod As Object
Set VBP = ActiveWorkbook.VBProject
Set newmod = VBP.VBComponents.Add(1)
Dim StartLine As Long
Dim cLines As Long
With ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
cLines = .CountOfLines + 1
.InsertLines cLines, _
"Private Sub Workbook_Open()" & Chr(13) & _
" Application.Calculation = xlManual" & Chr(13) & _
" Application.CalculateBeforeSave = False" & Chr(13) & _
" Application.DisplayFormulaBar = False" & Chr(13) & _
"Call Module1.ProtectAll" & Chr(13) & _
"End Sub"
End With
End Sub
The code I want to inject in addition to the code above is below (code found on another site). This allows me to track changes on the workbook that I share with others. I do not want to use Excel's built-in "Track Changes" feature.
Dim vOldVal
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim bBold As Boolean
If Target.Cells.Count > 1 Then Exit Sub
On Error Resume Next
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
If IsEmpty(vOldVal) Then vOldVal = "Empty Cell"
bBold = Target.HasFormula
With Sheet1
.Unprotect Password:="Passcode"
If .Range("A1") = vbNullString Then
.Range("A1:E1") = Array("CELL CHANGED", "OLD VALUE", _
"NEW VALUE", "TIME OF CHANGE", "DATE OF CHANGE")
End If
With .Cells(.Rows.Count, 1).End(xlUp)(2, 1)
.Value = Target.Address
.Offset(0, 1) = vOldVal
With .Offset(0, 2)
If bBold = True Then
.ClearComments
.AddComment.Text Text:= _
"Note:" & Chr(10) & "" & Chr(10) & _
"Bold values are the results of formulas"
End If
.Value = Target
.Font.Bold = bBold
End With
.Offset(0, 3) = Time
.Offset(0, 4) = Date
End With
.Cells.Columns.AutoFit
.Protect Password:="Passcode"
End With
vOldVal = vbNullString
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
vOldVal = Target
End Sub
How can I achieve this? What is the best and the most efficient way to do this?
I've tried splitting the code in chunks of 20 lines and create 3 "AddCode" sub-routines, but I get an error at "bBold = Target.HasFormula". I have searched the web for alternatives, but nothing seems to be working.
Thanks in advance.

This is an abbreviated version of what I'm doing to create on load code. I create the onload event, then add a new module.
Sub AddOnload()
''Create on load sub
With ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
.InsertLines 1, "Private Sub Workbook_Open()"
.InsertLines 2, " call CallMe"
.InsertLines 3, "End Sub"
End With
Call CreateCode
End Sub
''Add new module with code
Sub CreateCode()
Dim vbp As VBProject
Dim vbc As VBComponent
Dim strCode
Set vbp = Application.VBE.ActiveVBProject
Set vbc = vbp.VBComponents.Add(vbext_ct_StdModule)
vbc.Name = "tracker"
strCode = "Sub CallMe()" & vbCrLf & "End Sub"
vbc.CodeModule.AddFromString strCode
End Sub

Related

I have to click okay for message box 4 times

I'm not sure why, but when my if statement is false and my msgbox is called I have to click okay 4 times for it to go away. How do I correct this?
My code:
Option Explicit
Private tskCol As String
Private unitCol As String
Private Sub txtTask_Change()
End Sub
Public Sub UserForm_Initialize()
tskCol = Application.InputBox("Enter Column Letter for Task Names", Type:=2)
unitCol = Application.InputBox("Enter Column Letter for Number of Units", Type:=2)
End Sub
Private Sub cmdAdd_Click()
Dim LastRow As Long, i As Long
LastRow = ActiveSheet.Range(tskCol & Rows.Count).End(xlUp).Row
'Copy input values to sheet
For i = 2 To LastRow
If CStr(ActiveSheet.Range(tskCol & i).Value) = CStr(Me.txtTask.Value) Then
ActiveSheet.Range(unitCol & i).Value = Me.txtQuantity.Value
Else
MsgBox "Task Not Found!"
End If
Next i
'Clear input controls
Me.txtTask.Value = ""
Me.txtQuantity.Value = ""
End Sub
To answer your specific question, try changing this line on the Else statement:
Msgbox "Task Not Found"
to
If i = LastRow Then Msgbox "Task Not Found"
You might also want to put Exit For if the task is found. Refactoring IF statement:
If CStr(ActiveSheet.Range(tskCol & i).Value) = CStr(Me.txtTask.Value) Then
ActiveSheet.Range(unitCol & i).Value = Me.txtQuantity.Value
Exit For '/* no need to continue the loop, task is found */
Else
'/* only call msgbox if all rows are processed */
If i = LastRow Then Msgbox "Task Not Found"
End If

VBA won't call UserForm from inside its own workbook

I have a CMD button on my sheet with the following code:
Private Sub cmdBlastoff_Click()
UserForm2.Show vbModeless 'launch gateway userform
End Sub
This code worked for a long time, but is now generating "Error 9: Subscript out of range."
The userform I am trying to call (UserForm2) is located in the same workbook.
I will put the full code of the userform below in case it's relevant, but the code in its Userform_initialize sub is:
Private Sub userform_initialize()
Sheets("hiddensheet1").Range("B5").Value = "v7.04" 'sets version # in hidden sheet
FileNameChecker_local 'runs a sub (located below in the userform module) to determine the filename and path
ValueInjector 'runs a sub (located below in the userform module) to put some values into text fields on the userform
cmdBigGo.Font.Size = 15 'sets font size of a button
End Sub
As I said earlier, this was working until recently and I am out of ideas.
So far I have tried:
1) Finding some way to explicitly point to the exact location of
userform2 by specifying the workbook in front of it:
ActiveWorkbook.UserForm2.show (doesn't work for reasons that are
now obvious) I regard a more explicit call as the most likely fix,
but don't know how to do it
2) Removing vbModeless from the call button call
3) Explicitly setting the ActiveWorkbook to the one all my stuff is
stored on, which is where the call button sits (this shouldn't be
necessary, I know)
Any other ideas?
Full code of the UserForm2 (probably not relevant, all working prior to this problem arising):
Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
(ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As Long
'should check to see if there is an output folder in the directory where COGENT sits and if not create it
'should pull default filepath to the outputs folder from the hiddensheet
'should call data baster on terminate
'DONE should allow the user to change the default save location
'DONE should allow them to change the save location THIS time.
'DONE should pull filepath from hiddensheet, check against original (?) and
'DONE Should create a default filename
Public strFileFullName As String
Public strFileJustPath As String
Public strUserFolderName As String
Public strFileName As String
Public strRawDate As String
Public strDLlink As String
Public strDLdest As String
Public strDLlocalName As String
Public strDLNameOnWeb As String
Public strOpenURLPointer As String
Dim strSaveAsErrHandler As String
Dim strQueryID As String
Private Sub userform_initialize()
Sheets("hiddensheet1").Range("B5").Value = "v7.04" 'sets version # in hidden sheet
FileNameChecker_local 'runs a sub (located below in the userform module) to determine the filename and path
ValueInjector 'runs a sub (located below in the userform module) to put some values into text fields on the userform
cmdBigGo.Font.Size = 15 'sets font size of a button
End Sub
Private Sub chkCyberDiv_Click()
If chkCyberDiv.Value = True Then
'==Cyber OUs visible==
chkNDIO.Visible = True
txtQueryID.Value = "169436"
'==Other Div OUs invisible==
chkCivilDiv.Value = False
Else
chkNDIO.Visible = False
End If
End Sub
Private Sub chkCivilDiv_Click()
If chkCivilDiv.Value = True Then
'==Civil OUs visible==
chkCivilInfoSys.Visible = True
'==Other Div OUs invisible==
chkCyberDiv.Value = False
Else
chkCivilInfoSys.Visible = False
End If
End Sub
Sub cmdBigGo_Click()
'==========Check if SaveAsNewName worked and if not kill sub==========
SaveAsNewName
If strSaveAsErrHandler = "Filename/path not viable." Then
MsgBox strSaveAsErrHandler
Exit Sub
Else
'==========Startup==========
Application.ScreenUpdating = False
Sheets("LoadingData").Visible = True
Sheets("Launchpad").Visible = False
'==========Check for/create Temp Directory==========
If FileFolderExists(strFileJustPath & "\temp") = True Then
'MsgBox "temp Folder already exists."
Else
MkDir strFileJustPath & "\temp"
'MsgBox "temp Folder didn't exist, but it do now."
End If
'==========Download Section==========
'=====Set up===== 'big gap for now = 169436
strQueryID = txtQueryID.Value
strDLlink = "https://workbench.northgrum.com/xauth/login.aspx?&ActionPageID=37&ActionParameters=QueryID%3d" & strQueryID & "%26View%3d0%26OutputToExcel%3d1"
strDLdest = strFileJustPath & "\temp\dump.xlsx"
'=====Run=====
'MsgBox "cmdBigGo thinks strDLdest = " & strDLdest
Dim done
done = URLDownloadToFile(0, strDLlink, strDLdest, 0, 0)
'==========Copy Targets from temp file==========
Sheets("LoadingData").Select
copyPathName = strFileJustPath & "\temp\"
copyFileName = "dump.xlsx"
copyTabName = "Targets"
ControlFile = ActiveWorkbook.Name
Workbooks.Open FileName:=copyPathName & "\" & copyFileName
ActiveSheet.Name = copyTabName
Sheets(copyTabName).Copy After:=Workbooks(ControlFile).Sheets(1)
Windows(copyFileName).Activate
ActiveWorkbook.Close SaveChanges:=False
Windows(ControlFile).Activate
ActiveWorkbook.Sheets("Targets").Name = "COGENT Targets"
'^source: https://msdn.microsoft.com/en-us/library/office/ff194819.aspx
'==========Delete Temp Directory==========
On Error Resume Next
Kill copyPathName & "\*.*" ' delete all files in the folder
RmDir copyPathName ' delete folder
On Error GoTo 0
'==========Create Userform1 Button on "Targets"==========
Rows("1:1").RowHeight = 26
Dim btnCOGENT As Button
Set btnCOGENT = Sheets("COGENT Targets").Buttons.Add(10.5, 4.5, 84.75, 19.5)
With btnCOGENT
.OnAction = "CallUserform1"
.Characters.Text = "COGENT"
End With
With btnCOGENT.Characters(Start:=1, Length:=6).Font
.Name = "Calibri"
.FontStyle = "Regular"
.Size = 11
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = 1
End With
Sheets("COGENT Targets").Shapes("Button 1").ScaleWidth 0.7433628319, msoFalse, _
msoScaleFromTopLeft
'==========Finish up==========
Worksheets("COGENT Targets").Activate
Sheets("LoadingData").Visible = False
Application.ScreenUpdating = True
End If
UserForm1.Show vbModeless
End Sub
Private Sub SaveAsNewName()
strSaveAsErrHandler = ""
On Error GoTo ErrorHandler
'==========Save the file with a new name==========
Dim strExpectedFileFullName As String
strExpectedFileFullName = txtFilePath.Value & "\" & txtFileName & ".xlsm"
ActiveWorkbook.SaveAs strExpectedFileFullName
FileNameChecker_local 'get the new filename
Exit Sub
ErrorHandler:
'==========Error Handler==========
If Err.Number = 1004 Then
lblSaveAsText.Caption = "That name and location didn't work... Try using 'Browse' or 'Create Outbox."
lblSaveAsText.BackColor = &H8080FF
strSaveAsErrHandler = "Filename/path not viable."
Else
MsgBox "unknown error...email Owen.Britton#NGC.com; it's probably his fault."
strSaveAsErrHandler = ""
End If
End Sub
Sub FileNameChecker_local()
'==========Check Filename and SaveAs if needed==========
strFileJustPath = ActiveWorkbook.Path
strFileFullName = ActiveWorkbook.FullName
'==========Get Filename==========
Dim i As Integer
Dim intBackSlash As Integer, intPoint As Integer
For i = Len(strFileFullName) To 1 Step -1
If Mid$(strFileFullName, i, 1) = "." Then
intPoint = i
Exit For
End If
Next i
If intPoint = 0 Then intPoint = Len(strFileFullName) + 1
For i = intPoint - 1 To 1 Step -1
If Mid$(strFileFullName, i, 1) = "\" Then
intBackSlash = i
Exit For
End If
Next i
strFileName = Mid$(strFileFullName, intBackSlash + 1, intPoint - intBackSlash - 1)
'MsgBox "strFileName = " & strFileName & vbNewLine & _
"strFileJustPath = " & strFileJustPath & vbNewLine & _
"strFileFullName = " & strFileFullName & vbNewLine & _
"ran from userform2"
End Sub
Private Sub ValueInjector()
strRawDate = Format(Date, "mm-d-yy")
'==========Inject File Name==========
If strFileName = "COGENT Launchpad" Then
txtFileName.Value = "COGENT_Pull_" & strRawDate 'might be better to include query number\
lblSaveAsText.Caption = "Give your output a descriptive name. Here's a suggestion:"
Else
'txtFileName.Value = strFileName
lblSaveAsText.Caption = "This file should be named 'COGENT Launchpad.' Some features break if you rename it."
lblSaveAsText.BackColor = &H8080FF
'MsgBox "Please rename this file 'COGENT Launchpad'"
End If
'==========Inject File Path==========
Application.ScreenUpdating = False
If IsEmpty(Worksheets("Hiddensheet1").Range("B6")) Then
cmdCreateOutbox_click
Worksheets("Hiddensheet1").Range("B6") = strFileJustPath & "\Outbox"
txtFilePath.Value = Worksheets("Hiddensheet1").Range("B6")
Else
txtFilePath.Value = Worksheets("Hiddensheet1").Range("B6")
End If
Application.ScreenUpdating = True
Worksheets("Launchpad").Activate
End Sub
Private Sub cmdBrowse_Click()
FileNameChecker_local
GetFolder (strFileJustPath)
End Sub
Private Sub cmdMakeDefault_Click()
Worksheets("Hiddensheet1").Range("B6") = txtFilePath.Value
imgCheckMark.Visible = True
End Sub
Private Sub cmdCreateOutbox_click()
'MsgBox "looking for" & strFileJustPath & "\Outbox"
If FileFolderExists(strFileJustPath & "\Outbox") Then
MsgBox "Outbox Folder already exists."
Else
MsgBox "Outbox Folder did not exist, but it does now."
MkDir strFileJustPath & "\Outbox"
txtFilePath.Value = strFileJustPath & "\Outbox"
End If
End Sub
Function GetFolder(strFilePath As String) As String
Dim fldr As FileDialog
Dim strGetFolderOutput As String
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = strFilePath
If .Show <> -1 Then GoTo NextCode
strGetFolderOutput = .SelectedItems(1)
End With
NextCode:
GetFolder = strGetFolderOutput
txtFilePath.Value = strGetFolderOutput
Set fldr = Nothing
End Function
Private Sub userform_terminate()
Unload Me
End Sub
Somehow the hidden sheet got deleted, and it gets referred to before I check its existence and create it if missing. Thanks guys; I was barking up totally the wrong tree. Fixed and working.
Nothing was wrong with the calling of the userform at all.

Why does Userform freezes after hiding and showing it multiple times

Ok, i have question on hiding and showing userforms.
This link already answered it for me.
Problem is I encounter another problem.
When I go back to Userform1 it freezes and I can't do anything at all.
Why? Do i need to add something in the code?
Heres the summay of the code i used:
This code prompts user to enter username and password
Option Explicit
Private Sub CBu_Login_Click()
Dim ws As Worksheet, rng As Range, lrow As Long, find_value As String
Dim cel As Range
Set ws = ThisWorkbook.Sheets("UserName")
lrow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("A2:A" & lrow)
find_value = Me.TB_Username.Value
Set cel = rng.Find(What:=find_value, After:=ws.Range("A2"), LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not cel Is Nothing Then
If Me.TB_Password.Value = cel.Offset(0, 1).Value Then
Me.Hide
UF_Encoding.L_User.Caption = "Welcome " & cel.Offset(0, 2).Value & "!" & " You are logged in."
UF_Encoding.TB_Operator.Text = cel.Offset(0, 2).Value
UF_Encoding.TB_ESN_IMEI.Value = ""
UF_Encoding.CB_PrimaryCode.Value = ""
UF_Encoding.CB_SecondaryCode.Value = ""
UF_Encoding.TB_Remarks.Value = ""
UF_Encoding.TB_ESN_IMEI.SetFocus
UF_Encoding.Show
Else
MsgBox "Invalid Username/Password"
End If
Else
MsgBox "Invalid Username/Password"
End If
End Sub
This code is for logging out:
I used Listbox here so the user can select which action to take.
Private Sub LB_Options_AfterUpdate()
If Me.LB_Options.Value = "Log out" Then
Me.Hide
Me.LB_Options.Visible = False
UF_Login.TB_Username.Value = ""
UF_Login.TB_Password.Value = ""
UF_Login.Show
ElseIf Me.LB_Options.Value = "Change Password" Then
Me.Hide
Me.LB_Options.Visible = False
UF_Changepass.TB_User.Value = ""
UF_Changepass.TB_Newpass.Value = ""
UF_Changepass.TB_Oldpass.Value = ""
UF_Changepass.Show
ElseIf Me.LB_Options.Value = "Exit" Then
Me.Hide
wbDbase.Save
wbDbase.Close
wbEncoding.Save
wbEncoding.Close
Unload UF_Login
Unload UF_Changepass
Unload Me
End If
Well this does what i wan't. Log in, log out, change pass and exit.
But as I've, said the Forms freezes after 1st execution.
Example:
1. I initialize UF_Login and then UF_Encoding appears.
2. It works, all commandbuttons and text boxes works.
3. Then I log out using the list box.
4. When i log in again, it will show UF_Encoding but when i try to use the commanb buttons and text boxes, it doesn't work.
5. Strange thing is that the list box with log out, change pass and exit works.
I'm really having a hard time figuring out why.
Any help is appreciated.
Give this a try. It's "rough" code, and certainly needs refining, but it works, and should give you some ideas.
This goes in UF_Encoding
Option Explicit
'UF_Encoding form
Private msLBox As String
Private msUser As String
Public Property Let psUser(s As String)
msUser = s
End Property
Public Property Get psLBox() As String
psLBox = msLBox
End Property
Private Sub LB_Options_AfterUpdate()
msLBox = Me.LB_Options.Value
If Me.LB_Options.Value = "Log out" Then
Me.Hide
Me.LB_Options.Visible = False
UF_Login.TB_Username.Value = ""
UF_Login.TB_Password.Value = ""
ElseIf Me.LB_Options.Value = "Change Password" Then
Me.Hide
Me.LB_Options.Visible = False
UF_Changepass.TB_User.Value = ""
UF_Changepass.TB_Newpass.Value = ""
UF_Changepass.TB_Oldpass.Value = ""
ElseIf Me.LB_Options.Value = "Exit" Then
Me.Hide
' wbDbase.Save
' wbDbase.Close
' wbEncoding.Save
' wbEncoding.Close
' Unload UF_Login
' Unload UF_Changepass
' Unload Me
End If
End Sub
Private Sub UserForm_Activate()
Me.L_User.Caption = "Welcome " & msUser & "!" & " You are logged in."
Me.TB_Operator.Text = msUser
msLBox = "" 'reset each time form re-entered
Me.LB_Options.Visible = True
End Sub
Private Sub UserForm_Initialize()
Me.LB_Options.AddItem "Log out"
Me.LB_Options.AddItem "Change Password"
Me.LB_Options.AddItem "Exit"
Me.TB_ESN_IMEI.Value = ""
Me.CB_PrimaryCode.Value = ""
Me.CB_SecondaryCode.Value = ""
Me.TB_Remarks.Value = ""
Me.TB_ESN_IMEI.SetFocus
End Sub
This goes in UF_Login
Option Explicit
'UF_Login form
Private msUser As String
Public Property Get psUser() As String
psUser = msUser
End Property
Private Sub CBu_Login_Click()
Dim ws As Worksheet, rng As Range, lrow As Long, find_value As String
Dim cel As Range
Set ws = ThisWorkbook.Sheets("UserName")
lrow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("A2:A" & lrow)
find_value = Me.TB_Username.Value
Set cel = rng.Find(What:=find_value, After:=ws.Range("A2"), LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not cel Is Nothing Then
If Me.TB_Password.Value = cel.Offset(0, 1).Value Then
msUser = cel.Offset(0, 2).Value 'save user name
Me.Hide
Else
MsgBox "Invalid Username/Password"
End If
Else
MsgBox "Invalid Username/Password"
End If
End Sub
This goes in UF_Changepass
Option Explicit
'UF_Changepass form
Private Sub CMDok_Click()
Dim ws As Worksheet, rng As Range
Set ws = ThisWorkbook.Sheets("UserName")
ws.Columns("B:B").Find(Me.TB_Oldpass, , xlValues, xlWhole, , , False).Value = Me.TB_Newpass
Me.Hide
End Sub
Private Sub UserForm_Click()
This code goes in a regular module
Option Explicit
Dim fLogin As UF_Login
Dim fEnc As UF_Encoding
Dim fChg As UF_Changepass
Sub main()
Dim s As String
' initialize all 3 forms
Set fLogin = New UF_Login
Set fEnc = New UF_Encoding
Set fChg = New UF_Changepass
fLogin.Show '1st time
' re-display main form until done
Do
fEnc.psUser = fLogin.psUser 'pass user name to main form
fEnc.Show
s = fEnc.psLBox 'get listbox value
If s <> "Exit" Then showAuxForms s
Loop Until s = "Exit"
' done with forms
Unload fLogin
Unload fEnc
Unload fChg
Set fLogin = Nothing
Set fEnc = Nothing
Set fChg = Nothing
End Sub
Sub showAuxForms(s As String)
If s = "Log out" Then
fLogin.Show
ElseIf s = "Change Password" Then
fChg.Show
End If
End Sub
To allow multiple switches between UserForms, it is better to unload the forms you're not using and then just reload it when it's time to use it again. Something like:
Me.Hide '/* hide the initiating form first */
Load UF_Login '/* loads the form, but not shown */
With UF_Login
.TB_Username.Value = ""
.TB_Password.Value = ""
.Show
End With
Unload Me '/* unload the initiating form */
In the UF_Login, a code to view the UF_Encoding will be added to make it look like you're actually logging in and out of the form.
Private Sub CB_Login_Click()
'/* code to check log-in credentials goes here */
Me.Hide
Load UF_Encoding
UF_Encoding.Show
Unload Me
End Sub

Display old and new values for a cell

I have a worksheet that logs changes that uses have made to cells. It goes as follows
Public OldVal As String
Public NewVal As String
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Cells.Count > 1 Or IsEmpty(Target) Then Exit Sub
OldVal = Target.Value
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LDate As String
If Target.Cells.Count > 1 Then Exit Sub
NewVal = Target.Value
Sheets("corrections").Cells(Rows.Count, "A").End(xlUp)(2).Value = Now & "_Sheet " & ActiveSheet.Name & " Cell " & Target.Address(0, 0) & " was changed from '" & OldVal & "' to '" & NewVal & "'"
OldVal = ""
NewVal = ""
End Sub
The problem im having is that for some reason it will never display the previous value. it will output it only as Sheet FA Cell B5 was changed from '' to '12' even if say for example 10 was in the cell prviously.
I also was curious to know is there a way that you can have it so that this code is not running at all times. Id prefer to have a button you click and at that point it will initiate and start logging changes.
Thanks
I got your posted code to work with a very small change:
Public OldVal As String
Public NewVal As String
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Cells.Count > 1 Or IsEmpty(Target) Then Exit Sub
OldVal = Target.Value
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LDate As String
If Target.Cells.Count > 1 Then Exit Sub
NewVal = Target.Value
Application.EnableEvents = False
Sheets("corrections").Cells(Rows.Count, "A").End(xlUp)(2).Value = Now & "_Sheet " & ActiveSheet.Name & " Cell " & Target.Address(0, 0) & " was changed from '" & OldVal & "' to '" & NewVal & "'"
Application.EnableEvents = True
OldVal = ""
NewVal = ""
End Sub
For your second question, start with:
Application.EnableEvents = False
Hook your button onto a macro like this:
Sub StartLogging()
Application.EnableEvents = True
End Sub
Your code is working fine for me. As for the enable/disable macro, you just need to insert this line before (/above) each IF (in both of your macros). Optional check for a more appropriate cell to store the Yes/No option (rather than "X1"):
If Sheets("corrections").Range("X1") <> "Yes" Then Exit Sub
' where you can change X1 for a more appropriate cell
To create the buttons just add the shapes/objects and assign the macros below:
Sub Enable_Logs()
Sheets("corrections").Range("X1").Value = "Yes"
End Sub
Sub Disable_Logs()
Sheets("corrections").Range("X1").Value = "No"
End Sub
Note! To add buttons with macro assigned to them: press Alt + N, +SH and select a shape. Then, right click on the shape > Assign Macro (and select the corresponding macros). Note! for the 1st time you run the macro, you should manually set the "Yes" value in cell X1.
Thr problem why my OldVal was not showing up was that it was being held in array. So when I told it to look at OldVal(1, 1) it works just as it should. Thanks for the help. The final working code is:
Public OldVal As String
Public NewVal As String
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Sheets("corrections").Range("G1") <> "Yes" Then Exit Sub
OldVal = Target.Value2
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Sheets("corrections").Range("G1") <> "Yes" Then Exit Sub
If Target.Cells.CountLarge > 1 Then Exit Sub
NewVal = Target.Value
Sheets("corrections").Cells(Rows.Count, "A").End(xlUp)(2).Value = Now & "_Sheet " & ActiveSheet.Name & " Cell " & Target.Address(0, 0) & " was changed from '" & OldVal(1, 1) & "' to '" & NewVal & "'"
OldVal = ""
NewVal = ""
End Sub

Update sheet with data from userform

I have a table and I have the form I built.
the user pick a name and surname from the table by the combobox in form
the user need to choose from combobox "yes/no" about this name
I need a vba code (excel) so that it can find the name (after the user picked it) in the table
and then update the yes/no column by the correct row.
I created a module and added this:
Option Explicit
Public Sub update_sheet(workername As String)
'--> If the user was selected on the form update column F to Yes
Dim ws As Worksheet
Dim rowno As Long
Set ws = Sheets("workers")
With ws
rowno = .Range("C:C").Find(workername).Row
.Cells(rowno, 6).Value = "Yes"
End With
End Sub
On the form code:
Private Sub cb_select_change()
Call update_sheet(cb_select.Value)
End Sub
where your combo box is called cb_select
You'll need to do some work on this to make it into what you need, but it should get you started:
Private Sub CommandButton1_Click()
Dim rng_ToSearch As Excel.Range
Dim rng_Found As Excel.Range
On Error GoTo ErrorHandler
'Change this to the range that contains your names. I'm assuming that
'it's a single column and has the Yes/No column alongside.
Set rng_ToSearch = Sheet1.Range("MyTable_Names")
'Change the What argument to reflect the name of your form's
'control.
Set rng_Found = rng_ToSearch.Find(What:=Me.ComboBox1.Value, _
After:=rng_ToSearch.Range("A1"), LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'This shouldn't happen if you've populated the name selection
'box correctly and have not allowed users to add to it.
'This is left as an exercise for the reader.
If rng_Found Is Nothing Then
Err.Raise vbObjectError + 2000, , "Either the selected name was " _
& "not found in the list, or no selection was made."
End If
'Again, change the control name to your own.
rng_Found.Offset(0, 1) = Me.ComboBox2.Value
ExitPoint:
On Error Resume Next
Set rng_ToSearch = Nothing
Set rng_Found = Nothing
On Error GoTo 0
Exit Sub
ErrorHandler:
MsgBox "Error in updating users: " & Err.Number & vbCrLf & Err.Description
Resume ExitPoint
End Sub
THIS IS MY CODE SO FAR
Private Sub RefEdit1_BeforeDragOver(Cancel As Boolean, ByVal Data As msforms.DataObject, ByVal x As stdole.OLE_XPOS_CONTAINER, ByVal y As stdole.OLE_YPOS_CONTAINER, ByVal DragState As msforms.fmDragState, Effect As msforms.fmDropEffect, ByVal Shift As Integer)
End Sub
Private Sub ClsFrmE_Click()
Unload Me
End Sub
Private Sub cmdAdd_Click()
Dim lRow As Long
Dim ws As Worksheet
Set ws = Worksheets("workers")
'???รท? ?? ?????? ?????
If Trim(Me.cmbWN.Value) = "" Then
Me.cmbWN.SetFocus
MsgBox "???? ?? ????"
Exit Sub
End If
If Trim(Me.tbDate.Value) = "" Then
Me.tbDate.SetFocus
MsgBox "???? ????? ?????"
Exit Sub
End If
'copy the data to the database
'use protect and unprotect lines,
' with your password
' if worksheet is protected
With ws
' .Unprotect Password:="password"
If Trim(Me.dNdcmb.Value) = "????" Then
.Cells(lRow, 6).Value = 1
Else
.Cells(lRow, 6).Value = 0
End If
.Cells(lRow, 7).Value = Me.tbDate.Value
'.Cells(lRow, 2).Value = Me.cboPart.List(lPart, 1)
' .Protect Password:="password"
End With
'clear the data
Me.cmbWN.Value = ""
Me.tbDate.Value = ""
Me.cmbWN.SetFocus
ActiveWorkbook.Save
End Sub
Private Sub UserForm_Initialize()
Dim cFullName As Range
Dim cDnd As Range
Dim ws As Worksheet
Set ws = Worksheets("workers")
For Each cFullName In ws.Range("??????")
With Me.cmbWN
.AddItem cFullName.Value
.List(.ListCount - 1, 1) = cFullName.Offset(0, 1).Value
End With
Next cFullName
For Each cDnd In ws.Range("??????????")
With Me.dNdcmb
.AddItem cDnd.Value
End With
Next cDnd
Me.dNdcmb.Text = Me.dNdcmb.List(Me.dNdcmb.ListCount - 2)
Me.cmbWN.SetFocus
End Sub