Pick folder routine going to Error handler - Excel VBA - vba

Below is code that allows the user to choose a folder and opens files within the folder. It essentially does this:
On open, look for filepath saved in worksheet in workbook based on username. If doesn't exist, then prompt user to find folder, then save filepath in worksheet
From step 1, if filepath is found based on user, use that filepath
Error handler: From step 1, if filepath is found based on user, but that filepath is not in use anymore(i.e. user moved the folder to a different filepath), then have user find the folder again, then update existing record
What i'm experiencing is this:
When there's no entries in the sheet, then it will prompt user to
find the folder, but then proceed to the errorhandler and ask the
user to find the folder again
When there are entries in the sheet and the file path is working, the errorhandler is still opened and asks the user to find the
folder again
If I take out the errorhandler, everything is smooth. It's just that I want to cover the possibility of the user moving the folder , so I want the workbook to prompt the user to find where they moved the folder, and update the existing record in the workbook to the new path
What am I doing wrong here?
Private Sub Workbook_Open()
Dim wkb1 As Workbook
Dim sht1 As Worksheet
Dim wkb2 As Workbook
Dim sht2 As Worksheet
Dim vafiles As Variant
Dim filepath As String
Dim filepath2 As String
Dim filepath3 As String
Dim rw As Long
Dim ws As Worksheet
Dim lastrow As Long
Dim icounter As Long
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlManual
Set ws = Worksheets("Paths")
rw = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
Set wkb1 = ThisWorkbook
Set sht1 = wkb1.Sheets("Extract")
'======================================================
'Determine if Path was already saved before. If not, prompt user to choose folder
'======================================================
sal = Application.VLookup(Environ("username"), ws.Range("a:b"), 2, 0)
If IsError(sal) Then
MsgBox ("Please choose where your main folder is located. This will be stored so you won't need to look for it again.")
filepath = PICK_A_FOLDER()
ws.Cells(rw, 2) = PICK_A_FOLDER()
ws.Cells(rw, 1) = Environ("username")
Set wkb2 = Workbooks.Open(filepath & "\ Export.xlsx")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
Worksheets("Instructions").Activate
Application.Calculation = xlAutomatic
Else
'======================================================
'If filepath exists, use that one
'======================================================
filepath2 = sal
Set wkb2 = Workbooks.Open(filepath2 & "Export.xlsx")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
End If
'======================================================
'If user has moved their folder, we can find it again and update their record
'======================================================
On Error GoTo Errorhandler
Errorhandler:
MsgBox ("Looks like you've moved your Folder. Please find it so your record will be updated")
filepath3 = PICK_A_FOLDER()
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
For icounter = 2 To lastrow
If Cells(icounter, 1) = Environ("username") Then
Cells(icounter, 2) = PICK_A_FOLDER()
End If
Next icounter
Set wkb2 = Workbooks.Open(filepath3 & "")
Set sht2 = wkb2.Sheets("Sheet1")
sht2.Cells.Copy Destination:=sht1.Range("a1")
Application.CutCopyMode = False
wkb2.Close True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
Worksheets("Instructions").Activate
Application.Calculation = xlAutomatic
End Sub

Actually solved this by taking out the errorhandler and inserting another if statement that captures an invalid directory:
if dir(sal & "Export.xlsx") = "" then
write error handler code

When a SubRoutine performs more that one task you should consider extracting the individual tasks into separate SubRoutines.
In this way:
You can debug each task independently of the other tasks
The logic is simplified into smaller units
The code is easier to read
You can reduce clutter by placing these SubRoutines into separate modules
Possible code reuse
Another unapparent benefit is that by simplifying the function of a SubRoutine it is much easier to remember the routines pattern and reuse the pattern when a similar situation arises.
Note: I often use If Len(...) then which is analogous to If Len(...) > 0 then. I do this to reduce clutter.
Standard Module
Function getSharedFolder() As String
Dim f As Range
With Worksheets("Paths")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Environ("username"), After:=.Range("A1"), LookAt:=xlWhole)
If Not f Is Nothing Then
'Dir([PathName], vbDirectory) returns empty if the [PathName] isn't a folder
If Len(Dir(f.Offset(0, 1).Value, vbDirectory)) Then
If Right(f.Offset(0, 1), 1) = "\" Then
getSharedFolder = f.Offset(0, 1)
Else
getSharedFolder = f.Offset(0, 1) & "\"
End If
End If
End If
End With
End Function
Function setSharedFolder() As Boolean
Dim f As Range
Dim PathName As String
PathName = PickSharedFolder
If Len(PathName) Then
setSharedFolder = True
With Worksheets("Paths")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Environ("username"), After:=.Range("A1"), LookAt:=xlWhole)
If f Is Nothing Then Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Offset(1)
f.Value = Environ("username")
f.Offset(0, 1) = PathName
End With
End If
End Function
Function PickSharedFolder() As String
Application.FileDialog(msoFileDialogFolderPicker).ButtonName = "Select Folder"
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Title = "Select Main Folder Location"
If .Show = -1 And .SelectedItems.Count = 1 Then
PickSharedFolder = .SelectedItems(1)
Else: Exit Function
End If
End With
End Function
Sub ToggleEvents(EnableEvents As Boolean, Optional DisplayAlerts = True)
With Application
.DisplayAlerts = DisplayAlerts
.EnableEvents = EnableEvents
.ScreenUpdating = EnableEvents
.Calculation = IIf(EnableEvents, xlCalculationAutomatic, xlCalculationManual)
End With
End Sub
Sub UpdateWorkBook(FilePath As String)
Dim WSSource As Worksheet
With Workbooks.Open(FilePath)
Set WSSource = .Sheets("Sheet1")
If WSSource Is Nothing Then
MsgBox "Sheet1 not found in " & FILENAME, vbCritical, "Update Cancelled"
Else
WSSource.Copy Destination:=ThisWorkbook.Sheets("Extract").Range("A1")
End If
.Close True
End With
End Sub
Workbook Module
Private Sub Workbook_Open()
Const FILENAME As String = "Export.xlsx"
Const PROMPT As String = "Press [Yes] to continue or [No] to cancel"
Dim FilePath As String, Title As String, SharedFolder As String
ToggleEvents False, False
Do
SharedFolder = getSharedFolder()
If Len(SharedFolder) = 0 Then
Title = "Folder not found"
Else
FilePath = SharedFolder & FILENAME
If Len(Dir(FilePath)) = 0 Then Title = "File not found"
End If
If Len(SharedFolder) = 0 Then
If MsgBox(PROMPT:=PROMPT, Buttons:=vbYesNo, Title:=Title) = vbYes Then
setSharedFolder
Else
Exit Sub
End If
End If
Loop Until Len(Dir(FilePath))
UpdateWorkBook FilePath
ToggleEvents True, True
End Sub

Related

Looping through dynamic sheet names

I am looping through a bunch of files in my folder and trying to copy a static column and paste to a master sheet. However every sheet I am looping through is a different name.
I believe this part of the code has to be changed:
xlsFiles.Sheets("Sheet3").Columns("20").Copy Destination:=wsMaster.Sheets("Sheet1").Range("A" & r).Offset(1, 0).
What can I use in place of sheets("Sheet3") ?
Here is the full code:
Option Explicit
Dim wsMaster As Workbook, csvFiles As Workbook
Dim Filename As String
Dim File As Integer
Dim r As Long
Public Sub Consolidate()
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = True
.Title = "Select files to process"
.Show
If .SelectedItems.Count = 0 Then Exit Sub
Set wsMaster = ActiveWorkbook
For File = 1 To .SelectedItems.Count
Filename = .SelectedItems.Item(File)
If Right(Filename, 5) = ".csv*" Then
Set csvFiles = Workbooks.Open(Filename, 0, True)
r = wsMaster.Sheets("Sheet1").UsedRange.Rows.Count
csvFiles.Sheets(1).Columns("col name").Copy Destination:=wsMaster.Sheets("Sheet1").Range("A" & r).Offset(1, 0)
csvFiles.Close SaveChanges:=False 'close without saving
End If
Next File 'go to the next file and repeat the process
End With
Set wsMaster = Nothing
Set csvFiles = Nothing
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
The answer you already got by #sktneer in the comments above.
You could shorten and "clean-up" your If section code a little, try the code below:
If Right(Filename, 5) = ".xls*" Then
Set xlsFiles = Workbooks.Open(Filename, 0, True)
r = wsMaster.Sheets("Sheet1").UsedRange.Rows.Count
xlsFiles.Sheets(3).Columns("20").Copy Destination:=wsMaster.Sheets("Sheet1").Range("A" & r).Offset(1, 0)
xlsFiles.Close SaveChanges:=False 'close without saving
End If

Find if workbook for individual user exists, if workbook does not exist, create a new workbook with template

I have a data file that I am trying to make for each person in my work group. The data file needs to be identical to a master file as each persons data will be collected into said master file as well as an individual data file.
So far, I have the following code where I try to identify whether a user already has a workbook. I want the created workbook to have the same first four sheets as the master workbook.
The folder specified only contains the "DataFile Master" Workbook so I wouldn't expect the macro to take longer than ~5 seconds. However, when I try to run the macro, the workbook becomes non responsive.
The program does not induce an error report or indicate something to debug.
Does anyone have any ideas?
Sub StoreToPersonal()
Application.ScreenUpdating = False
ckIndWkbk = False
folderpath = "\\netappa\Path\MACRO UPDATE WORKBOOKS" 'change to suit
If Right(folderpath, 1) <> "\" Then folderpath = folderpath + "\"
filename = Dir(folderpath & "*.xlsm")
'Look through path length and find if user has an individual Workbook with a Boolean Statement
Do While filename <> ""
If InStr(filename, Environ("Username")) Then
ckIndWkbk = True
Else
End If
Loop
If ckIndWkbk = False Then
Set wb = Workbooks.Open("\\netappa\Path\MACRO UPDATE WORKBOOKS\DataFile Master.xlsm")
ws = wb.Sheets.Count
For Each ws In wb
If ws.Index > 4 Then
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End If
Next ws
wb.SaveAs ("\\netappa\Path\MACRO UPDATE WORKBOOKS\\DataFile For " & Environ("Username"))
End If
Application.ScreenUpdating = True
End Sub
The first Dir call sets the parameters and return the first file in the directory. You need to use the Dir in your Do Loop to return subsequent files.
Note: I added Exit Do to after the condition is met.
MSDN Dir Function
Sub StoreToPersonal()
Application.ScreenUpdating = False
ckIndWkbk = False
folderpath = "\\netappa\Path\MACRO UPDATE WORKBOOKS" 'change to suit
If Right(folderpath, 1) <> "\" Then folderpath = folderpath + "\"
Filename = Dir(folderpath & "*.xlsm")
'Look through path length and find if user has an individual Workbook with a Boolean Statement
Do While Filename <> ""
If InStr(Filename, Environ("Username")) Then
ckIndWkbk = True
Exit Do
End If
Filename = Dir
Loop
If ckIndWkbk = False Then
Set wb = Workbooks.Open("\\netappa\Path\MACRO UPDATE WORKBOOKS\DataFile Master.xlsm")
ws = wb.Sheets.Count
For Each ws In wb
If ws.Index > 4 Then
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End If
Next ws
wb.SaveAs ("\\netappa\Path\MACRO UPDATE WORKBOOKS\\DataFile For " & Environ("Username"))
End If
Application.ScreenUpdating = True
End Sub

VBA code not stable

It started on Monday this week, when I finished with my code,the codes purpose was to pull data from a specific sheet in a specific folder from all spreadsheets in that folder.
But just last night he started crashing excel spreadsheet every time i pushed the run button.
Any idea why?
Option Explicit
Sub ImportSheet()
Dim i As Integer
Dim SourceFolder As String
Dim FileList As Variant
Dim GrabSheet As String
Dim FileType As String
Dim ActWorkBk As String
Dim ImpWorkBk As String
Dim NoImport As Boolean
Application.EnableEvents = False
SourceFolder = "C:\Users\Jarryd.Ward\Desktop\Test\"
FileType = "*.xlsx"
GrabSheet = "Summary"
FileList = ListFiles(SourceFolder & "/" & FileType)
Application.ScreenUpdating = False
ActWorkBk = ActiveWorkbook.Name
NoImport = False
For i = 1 To UBound(FileList)
Workbooks.Open (SourceFolder & "\" & FileList(i))
ImpWorkBk = ActiveWorkbook.Name
On Error Resume Next
ActiveWorkbook.Sheets(GrabSheet).Select
If Err > 0 Then
NoImport = True
GoTo nxt
End If
Err.Clear
On Error GoTo 0
ActiveWorkbook.Sheets(GrabSheet).Copy After:=Workbooks(ActWorkBk).Sheets(Workbooks(ActWorkBk).Sheets.Count)
ActiveSheet.Name = ImpWorkBk
On Error Resume Next
ActiveSheet.Name = FileList(i) & " - " & GrabSheet
Err.Clear
On Error GoTo 0
nxt:
Workbooks(ImpWorkBk).Activate
Application.DisplayAlerts = False
ActiveWorkbook.Saved = True
ActiveWorkbook.Close SaveChanges:=False
Application.DisplayAlerts = True
Workbooks(ActWorkBk).Activate
Next i
Application.ScreenUpdating = True
End Sub
Try opening and closing your files this way to see if it helps. It should minimize the calls to activate this or that. And closing out by variable instead of activesheet will insure that your code isn't trying to close the main workbook by accident.
Sub testOpen()
Dim manyWBs As Workbook
Dim myWB As Workbook
Set myWB = ThisWorkbook
For Each file In folder
Set manyWBs = Workbooks.Open("C:\temp\filename")
' do events.......
manyWBs.Worksheets("Sheet1").Range("A1:B13").Copy _
Destination:=myWB.Worksheets("Sheet1").Range("A1:b13")
manyWBs.Close
Set manyWBs = Nothing
Next file
Set myWB = Nothing
End Sub

VBA, Delimit excel files by "|" upon opening

I have a macro that opens .txt files in excel, is there a way to delimit them upon opening? Note: Multiple files are open, so something like active workbooks split by "|", not sure how to split. UserInput is in my dictionary and is the file picker.
This is what I currently have:
Sub Rec()
Dim wb As Workbook, fileNames As Object, errCheck As Boolean
Dim ws As Worksheet, wks As Worksheet, wksSummary As Worksheet
Dim y As Range, intRow As Long, i As Integer
' Turn off screen updating and automatic calculation
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'get user input for files to search
Set fileNames = CreateObject("Scripting.Dictionary")
errCheck = UserInput.FileDialogDictionary(fileNames)
If errCheck Then
Exit Sub
End If
For Each Key In fileNames 'loop through the dictionary
On Error Resume Next
Set wb = Workbooks.Open(fileNames(Key))
If Err.Number <> 0 Then
Set wb = Nothing ' or set a boolean error flag
End If
On Error GoTo 0 ' or your custom error handler
Next 'End of the fileNames loop
Set fileNames = Nothing
' Reset system settings
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = True
.Visible = True
End With
End Sub
Any help would be appreciated.
Providing you are using Excel 2010 or later the following should work (the primary change is to your WorkBooks.Open statement):
Sub Rec()
Dim fileNames As Object, errCheck As Boolean
Dim ws As Worksheet, wks As Worksheet, wksSummary As Worksheet
Dim y As Range, intRow As Long, i As Integer
' Turn off screen updating and automatic calculation
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'get user input for files to search
Set fileNames = CreateObject("Scripting.Dictionary")
errCheck = UserInput.FileDialogDictionary(fileNames)
If errCheck Then
Exit Sub
End If
For Each Key In fileNames 'loop through the dictionary
On Error Resume Next
Workbooks.OpenText Filename:=filenames(Key), _
DataType:=xlDelimited, _
Other:=True, _
OtherChar:="|"
On Error GoTo 0 ' or your custom error handler
Next 'End of the fileNames loop
Set fileNames = Nothing
' Reset system settings
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = True
.Visible = True
End With
End Sub
As Workbooks.OpenText will display an error message if it can't open the file, you can probably get rid of your error handler entirely (I have done so in the edited version above), or you could suppress OpenText's automatic error message by setting Application.DisplayAlerts to False, and then continue to have your own error handler. (It depends on what you want to do if the file doesn't exist.)
Split it and loop through it
Sub Break_String()
Dim WrdArray() As String
Dim text_string As String
text_string = "A|B|C|D"
WrdArray() = Split(text_string, "|")
For i = LBound(WrdArray) To UBound(WrdArray)
strg = strg & vbNewLine & "Part No. " & i & " - " & WrdArray(i)
Next i
MsgBox strg
End Sub

Compile a list/ summary of a specific cell from multiple workbooks with VBA?

I have multiple workbooks in the same layout. In the cell "I8" I have calculated a specific value that I want to compile from all workbooks.
Here is an example of my code:
Sub Code()
Dim file As String
Dim wbResults As Workbook
Dim myPath As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
myPath = "C:\Test\"
file = Dir$(myPath & "*.xls*")
While (Len(file) > 0)
Set wbResults = Workbooks.Open(Filename:=myPath & file, UpdateLinks:=0)
With wbResults.Worksheets(Split(file, ".")(0))
With .Range("I8")
.Formula = "=10^(D28+(I7*I2))"
End With
End With
wbResults.Close SaveChanges:=True
file = Dir
Wend
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I would like to add to this code and compile a list in another excel workbook where column A puts the name of the file of a workbook and column B puts the value of "I8" in that respective workbook.
Here is my answer:
Sub Code()
Dim file As String
Dim wbResults As Workbook
Dim myPath As String
myPath = "C:\Test\"
'---------------- Create a new workbook then save it ----------------
Dim WBSummary As Workbook
Set WBSummary = Excel.Application.Workbooks.Add
WBSummary.SaveAs myPath & "WBSummary.xls"
'--------------------------------------------------------------------
Application.ScreenUpdating = False
Application.DisplayAlerts = False
file = Dir$(myPath & "*.xls*")
Dim i As Long 'To update row number in WBSummary
While (Len(file) > 0)
i = i + 1
If file <> "WBSummary.xls" Then
Set wbResults = Workbooks.Open(Filename:=myPath & file, UpdateLinks:=0)
With wbResults.Worksheets(Split(file, ".")(0))
With .Range("I8")
.Formula = "=10^(D28+(I7*I2))"
.Calculate 'To update value in "I8"
WBSummary.Worksheets(1).Cells(i, 1).Value = file
WBSummary.Worksheets(1).Cells(i, 2).Value = .Value
End With
End With
wbResults.Close SaveChanges:=True
End If
file = Dir
Wend
WBSummary.Close True 'Close and Save WBSummary
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub