I have found that code (on: http://www.siddharthrout.com/2011/07/29/excel-data-validationcreate-dynamic-dependent-lists-vba/) really useful:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long, LastRow As Long, n As Long
Dim MyCol As Collection
Dim SearchString As String, TempList As String
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Find LastRow in Col A
LastRow = Range("A" & Rows.Count).End(xlUp).Row
If Not Intersect(Target, Columns(1)) Is Nothing Then
Set MyCol = New Collection
'~~> Get the data from Col A into a collection
For i = 1 To LastRow
If Len(Trim(Range("A" & i).Value)) <> 0 Then
On Error Resume Next
MyCol.Add CStr(Range("A" & i).Value), CStr(Range("A" & i).Value)
On Error GoTo 0
End If
Next i
'~~> Create a list for the DV List
For n = 1 To MyCol.Count
TempList = TempList & "," & MyCol(n)
Next
TempList = Mid(TempList, 2)
Range("D1").ClearContents: Range("D1").Validation.Delete
'~~> Create the DV List
If Len(Trim(TempList)) <> 0 Then
With Range("D1").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=TempList
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
'~~> Capturing change in cell D1
ElseIf Not Intersect(Target, Range("D1")) Is Nothing Then
SearchString = Range("D1").Value
TempList = FindRange(Range("A1:A" & LastRow), SearchString)
Range("E1").ClearContents: Range("E1").Validation.Delete
If Len(Trim(TempList)) <> 0 Then
'~~> Create the DV List
With Range("E1").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=TempList
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
LetsContinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
'~~> Function required to find the list from Col B
Function FindRange(FirstRange As Range, StrSearch As String) As String
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Dim strTemp As String
Set aCell = FirstRange.Find(what:=StrSearch, LookIn:=xlValues, _
lookat:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Do While ExitLoop = False
Set aCell = FirstRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Else
ExitLoop = True
End If
Loop
FindRange = Mid(strTemp, 2)
End If
End Function
That code works but when I try to put the DV list to another sheet and change the cells to write on, it doesn't work correctly...
When I select the option what I want to the list, the selected option is not written on the cell.
So the program runs without any problem but the result, it's not what i want.
The rearranged code is:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long, LastRow As Long, n As Long
Dim MyCol As Collection
Dim SearchString As String, Templist As String
Application.EnableEvents = False
On Error GoTo Whoa
' Find LastRow in Col A
LastRow = Sheet2.Range("A" & Rows.Count).End(xlUp).Row
If Not Intersect(Target, Columns(1)) Is Nothing Then
Set MyCol = New Collection
' Get the data from Col A into a collection
For i = 2 To LastRow
If Len(Trim(Sheet2.Range("A" & i).Value)) <> 0 Then
On Error Resume Next
MyCol.Add CStr(Sheet2.Range("A" & i).Value), CStr(Sheet2.Range("A" & i).Value)
On Error GoTo 0
End If
Next i
' Create a list for the Data Validation List
For n = 1 To MyCol.Count
Templist = Templist & "," & MyCol(n)
Next
Templist = Mid(Templist, 2)
Range("A2").ClearContents: Range("A2").Validation.Delete
' Create the Data Validation List
If Len(Trim(Templist)) <> 0 Then
With Range("A2").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:=Templist
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
' Capturing change in cell A2
ElseIf Not Intersect(Target, Range("A2")) Is Nothing Then
SearchString = Range("A2").Value
Templist = FindRange(Sheet2.Range("A2:A" & LastRow), SearchString)
Range("B2").ClearContents: Range("B2").Validation.Delete
If Len(Trim(Templist)) <> 0 Then
' Create the DV List
With Range("B2").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:=Templist
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
LetsContinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
' Function required to find the list from Col B
Function FindRange(FirstRange As Range, StrSearch As String) As String
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Dim strTemp As String
Set aCell = FirstRange.Find(what:=StrSearch, LookIn:=xlValues, lookat:=xlWhole, SearchOrder:= _
xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Do While ExitLoop = False
Set aCell = FirstRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Else
ExitLoop = True
End If
Loop
FindRange = Mid(strTemp, 2)
End If
End Function
Is there somebody who has any idea if I have to change something more? Is there something tricky that I'm missing?
Related
I´ve been searching for a solution to create a dropdownlist in ColumnC (with start from row 2) if there is value in ColumnA same row.
But all I was able to find is how to create one dropdownlist using VBA.
Sub DVraschwab()
Dim myList$, i%
myList = ""
For i = 1 To 7
myList = myList & "ListItem" & i & ","
Next i
myList = Mid(myList, 1, Len(myList) - 1)
With Range("A5").Validation
.Delete
.Add _
Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Formula1:=myList
End With
End Sub
Is this possible? And how should I begin?
The dropdownlist should contain "Yes" and "No" and No would be standard.
This is code that execute when I have written anythins in A Col:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("A:A")) Is Nothing Then Exit Sub
Application.EnableEvents = False 'to prevent endless loop
On Error GoTo Finalize 'to re-enable the events
For Each columnAcell In Target.Cells
columnAcell.Offset(0, 3) = Mid(columnAcell, 2, 3)
If IsEmpty(columnAcell.Value) Then columnAcell.Offset(0, 4).ClearContents
Next
Application.ScreenUpdating = False
Dim w1 As Worksheet, w2 As Worksheet
Dim c As Range, FR As Variant
Set w1 = Workbooks("Excel VBA Test.xlsm").Worksheets("AP_Input")
Set w2 = Workbooks("Excel VBA Test.xlsm").Worksheets("Datakom")
For Each c In w1.Range("D2", w1.Range("D" & Rows.Count).End(xlUp))
FR = Application.Match(c, w2.Columns("A"), 0)
If IsNumeric(FR) Then c.Offset(, 1).Value = w2.Range("B" & FR).Value
Next c
Call Modul1.DVraschwab
If Target.Column = 1 Then
If Target.Value = vbNullString Then
Target.Offset(, 2).Clear
End If
End If
Finalize:
Application.EnableEvents = True
End Sub
The module I call is the dropdown you helped me with:
Sub DVraschwab()
Dim myList As String, r As Range
myList = "Yes,No"
For Each r In Range("A2", Range("A" & Rows.Count).End(xlUp))
If r.Value <> vbNullString Then
With r.Offset(, 2).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=myList
End With
r.Offset(, 2).Value = Split(myList, ",")(1)
End If
Next r
End Sub
Do you mean like this? You basically just need a loop added to your code to check column A.
Sub DVraschwab()
Dim myList As String, r As Range
myList = "Yes,No"
For Each r In Range("A2", Range("A" & Rows.Count).End(xlUp))
If r.Value <> vbNullString Then
With r.Offset(, 2).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=myList
End With
r.Offset(, 2).Value = Split(myList, ",")(1)
End If
Next r
End Sub
'this in the relevant sheet module
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 and target.row>1 Then
If Target.Value = vbNullString Then
Target.Offset(, 2).Clear
End If
End If
End Sub
This code will set the validation and write the default value in each cell.
Sub DVraschwab()
' 10 Jan 2018
Const MyList As String = "Yes,No"
Dim Rl As Long, R As Long
With Worksheets("Duplicates") ' replace with your sheet's name
' change column from "A" if not applicable
Rl = .Cells(.Rows.Count, "A").End(xlUp).Row
For R = 2 To Rl
With .Cells(R, 3).Validation
.Delete
.Add Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Formula1:=MyList
End With
.Cells(R, 3).Value = Split(MyList, ",")(1)
Next R
End With
End Sub
I am having trouble with getting a data validation list to adjust based on the last column from content in row 5.
Here is what i have currently.
Sub DataRange_F() 'Foundation Drop Down List
Application.ScreenUpdating = False
Dim LastCol As Long
Dim Rng As Range
Dim WholeRng As Range
Dim ws As Worksheet
Dim wsR As Worksheet
Set ws = ThisWorkbook.Worksheets("Add New")
Set wsR = ThisWorkbook.Worksheets("Foundation Plates")
wsR.Activate
Set Rng = Cells
LastCol = Rng.Find(What:="*", After:=Rng.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
Set WholeRng = Range(Cells(5, "C"), Cells(5, LastCol))
ws.Activate
With ws.Range("E8").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=WholeRng
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Set ws = Nothing
Application.ScreenUpdating = True
End Sub
It keeps stopping at the Formula1:= part. This is where i am stuck. How can i add my range in that Formula? Or is there another way?
Thanks
Try it like this...
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:="=" & "'" & wsR.Name & "'!" & WholeRng.Address
Try it as,
..., Formula1:=Chr(61) & WholeRng.Cells(1).Address(external:=true), Formula2:=Chr(61) & WholeRng.Cells(WholeRng.Cells.Count).Address(external:=true)
This is what i got to work.
Function GetColumnLetter(colNum As Long) As String
Dim vArr
vArr = Split(Cells(1, colNum).Address(True, False), "$")
GetColumnLetter = vArr(0)
End Function
Sub DataRange()
Application.ScreenUpdating = False
Dim startCol As String
Dim startRow As Long
Dim lastCol As Long
Dim myCol As String
Dim rng As Range
Dim cell As Range
Dim sht2 As Worksheet
Set sht2 = ThisWorkbook.Worksheets("Foundation Plates")
Dim sht7 As Worksheet
Set sht7 = ThisWorkbook.Worksheets("Legend")
Call Unprotect
sht2.Activate
startCol = "C"
startRow = 5
lastCol = sht2.Cells(5, sht2.Columns.Count).End(xlToLeft).Column
myCol = GetColumnLetter(lastCol)
Set rng = sht2.Range(startCol & startRow & ":" & myCol & "5")
'For error checking the range
'MsgBox rng.Address
sht7.Activate
With sht7.Range("F8").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:="=" & "'" & sht2.Name & "'!" & rng.Address
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
Call Protect
sht2.Activate
Set sht2 = Nothing
Set sht7 = Nothing
Set rng = Nothing
Application.ScreenUpdating = True
End Sub
I'm doing an office project where i need to create a macro.
I have a folder with 30 subfolders each named after our branches. For example- Chicago branch, New York branch etc. Each subfolder contains a number of workbooks and each workbook has a number of worksheet full of data.
I made a macro to extract a number of cells from the worksheet called "Menu" and one cell from the worksheet called "score" and paste it in a new workbook.
I have researched online and made two separate macros to get the data from the two seperate worksheets. But it only works if I select all the files I want inside a subfolder.
I also found some code to access folders inside subfolders but I couldn't compile it with my current code. In addition, I couldn't join the two macros I made, so it'd require only one button instead of two.
Now, I need a macro which will ask me to select a folder and go to the subfolders and folders inside the subfolders by itself and consolidate the data in a new workbook BUT in separate worksheets based on the Subfolders( the branch named ones, not the folders inside subfolders.
The data extracted from workbooks in the folders inside subfolders need to be in the worksheet named after the subfolder.) The idea is to have to press the command button once to get all the data extracted from that folder and subfolders inside at once as its too hectic to use my code 30 times for 30 subfolders to get data of 30 branches.
"Macro for extracting data from the worksheet MENU of each workbook"
Private Sub CommandButton1_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
ShName = "Menu" '<---- Change
Set Rng = Range("B9:b13") '<---- Change
'Select the files with GetOpenFilename
FileNameXls = Application.GetOpenFilename(filefilter:="Excel Files, *.xl*", _
MultiSelect:=True)
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 1
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("b2").Select
ActiveCell.FormulaR1C1 = "Client Name"
Range("C2").Select
ActiveCell.FormulaR1C1 = "Occupation"
Range("D2").Select
ActiveCell.FormulaR1C1 = "Date"
Range("E2").Select
ActiveCell.FormulaR1C1 = "Insured Location"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Serveyed by"
Range("B1").Select
ActiveCell.FormulaR1C1 = "=""Property Risk Scores Updated as at """
Rows("1:1").RowHeight = 27.75
Range("B1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("C1").Select
ActiveCell.FormulaR1C1 = "=TODAY()"
Range("c1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("b2:f2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Date", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
End Sub
"Macro for extracting data from the worksheet SCORE of each workbook"
Private Sub CommandButton2_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
ShName = "score" '<---- Change
Set Rng = Range("f65") '<---- Change
'Select the files with GetOpenFilename
FileNameXls = Application.GetOpenFilename(filefilter:="Excel Files, *.xl*", _
MultiSelect:=True)
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 6
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("g2").Select
ActiveCell.FormulaR1C1 = "Score"
Range("g2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Score", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
End Sub
#dave I'm posting this as an answer because it's too long to post as a comment. Can you please check which parts need correction? Thanks a lot!
Also I needed a code that will put the branch data in different worksheets. For example in sheet 1 will contain all the info I extracted from X branch folder,sheet 2 will contain all the info I extracted from Y branch folder.
Private Sub CommandButton1_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
Dim oSheet: Set oSheet = ThisWorkbook.Worksheets("Sheet to copy to in here")
Dim oFso: Set oFso = CreateObject("Scripting.FileSystemObject")
Dim oFolder: Set oFolder = oFso.GetFolder("Path to Desktop Branch Data folder in here")
Dim oSubFolder, oBranchWorkbook, oWorksheet
For Each oSubFolder In oFolder.SubFolders
Debug.Print "Looking inside " & oSubFolder.Name
Set oBranchWorkbook = Workbooks.Open(oSubFolder.Path & "*.xl*")
' Now you have the Info.xls from whichever branch folder we are in open
Set oWorksheet = oBranchWorkbook.Worksheets("Menu")
' Extract whatever you need from Menu to the current workbook, e.g.
oSheet.Range("B2").Value = oWorksheet.Range("B9:b13").Value
' Once you complete the Menu extract, change oWorksheet to point at Score
Set oWorksheet = oBranchWorkbook.Worksheets("Score")
' Extract whatever you need from Score to the current workbook, e.g.
oSheet.Range("G2").Value = oWorksheet.Range("F65").Value
'Once you have completed all the extracts you need, close the branch workbook
oBranchWorkbook.Close
Next ' Move onto next subfolder and repeat the process...
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 1
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("b2").Select
ActiveCell.FormulaR1C1 = "Client Name"
Range("C2").Select
ActiveCell.FormulaR1C1 = "Occupation"
Range("D2").Select
ActiveCell.FormulaR1C1 = "Date"
Range("E2").Select
ActiveCell.FormulaR1C1 = "Insured Location"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Serveyed by"
Range("g2").Select
ActiveCell.FormulaR1C1 = "Score"
Range("B1").Select
ActiveCell.FormulaR1C1 = "=""Property Risk Scores Updated as at """
Rows("1:1").RowHeight = 27.75
Range("B1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("C1").Select
ActiveCell.FormulaR1C1 = "=TODAY()"
Range("c1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("b2:g2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Date", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Score", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
Next
End Sub
Okay, I think I understand the requirement. Try something along these lines?
Dim oSheet
Dim oFso : Set oFso = CreateObject("Scripting.FileSystemObject")
Dim oFolder : Set oFolder = oFso.GetFolder("Path to Desktop Branch Data folder in here")
Dim oSubFolder, oBranchWorkbook, oWorksheet, iSheet
iSheet = 1
For Each oSubFolder in oFolder.SubFolders
Debug.Print "Looking inside " & oSubFolder.Name
' Set the sheet to copy to (1 on the first, 2 on the second etc)
' this would be better if the sheets were named for each branch folder
' as then instead of iSheet you could use oSubFolder.Name and it wouldn't matter if things were out of order for some reason...
Set oSheet = ThisWorkbook.Worksheets(iSheet)
For Each oFile in oSubFolder.Files
If Right(oFile.Name,3) = "xls" or Right(oFile.Name, 4) = "xlsx" Then
Set oBranchWorkbook = Workbooks.Open(oSubFolder.Path & oFile.Name)
' Now you have the Info.xls from whichever branch folder we are in open
Set oWorksheet = oBranchWorkbook.Worksheets("Menu")
' Extract whatever you need from Menu to the current workbook, e.g.
oSheet.Range("A1").Value = oWorksheet.Range("B1").Value
' Once you complete the Menu extract, change oWorksheet to point at Score
Set oWorksheet = oBranchWorkbook.Worksheets("Score")
' Extract whatever you need from Score to the current workbook, e.g.
oSheet.Range("A1").Value = oWorksheet.Range("B1").Value
'Once you have completed all the extracts you need, close the branch workbook
oBranchWorkbook.Close
End If
Next
iSheet = iSheet + 1 ' increment sheet counter
Next ' Move onto next subfolder and repeat the process...
My plan is to enter data on a specific sheet(List) and automatically sort by alphabetical order, then create a data validation on the first sheet (TicketSheet).
When I enter any date and save I can't open the file again because it crashes.
I developed the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("$A:$F")) Is Nothing Then
Dim x As Range
Set x = Cells(2, Target.Column)
Dim y As Range
Set y = Cells(1000, Target.Column)
If Target.Column = 1 Or Target.Column = 4 Or Target.Column = 6 Then
Range(x, y).Sort Key1:=Target, Order1:=xlAscending, Header:=xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End If
End If
Call AddData
Call AddData1
Call AddData2
End Sub
Sub AddData()
Dim Lrow As Single
Dim Selct As String
Dim Value As Variant
Lrow = Worksheets("List").Range("A" & Rows.Count).End(xlUp).Row
For Each Value In Range("A2:A" & Lrow)
Selct = Selct & "," & Value
Next Value
Selct = Right(Selct, Len(Selct) - 1)
With Worksheets("TicketSheet").Range("C4").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=Selct
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End Sub
Sub AddData1()
Dim Lrow1 As Single
Dim Selct1 As String
Dim Value As Variant
Lrow1 = Worksheets("List").Range("D" & Rows.Count).End(xlUp).Row
For Each Value In Range("D2:D" & Lrow1)
Selct1 = Selct1 & "," & Value
Next Value
Selct1 = Right(Selct1, Len(Selct1) - 1)
With Worksheets("TicketSheet").Range("C3").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=Selct1
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End Sub
Sub AddData2()
Dim Lrow2 As Single
Dim Selct2 As String
Dim Value As Variant
Lrow2 = Worksheets("List").Range("F" & Rows.Count).End(xlUp).Row
For Each Value In Range("F2:F" & Lrow2)
Selct2 = Selct2 & "," & Value
Next Value
Selct2 = Right(Selct2, Len(Selct2) - 1)
With Worksheets("TicketSheet").Range("C5").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=Selct2
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End Sub]
First off, you need to disable events. The Worksheet_Change event macro is triggered by a change of values. If you are going to start changing values inside a Worksheet_Change then disabling events stops the macro from triggering itself.
Additionally, the Target is the cell or cells that have been changed. Your code does not allow for the latter; it only deals with situations where Target is a single cell. For the time being, discard large changes (like those in a row deletion or sort operation).
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Not Intersect(Target, Range("$A:$F")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Dim x As Range, y As Range
Set x = Cells(2, Target.Column)
Set y = Cells(1000, Target.Column)
If Target.Column = 1 Or Target.Column = 4 Or Target.Column = 6 Then
'you really should know if you have column header labels or not
Range(x, y).Sort Key1:=Target, Order1:=xlAscending, _
Header:=xlGuess, OrderCustom:=1, _
MatchCase:=False, Orientation:=xlTopToBottom
Call AddData
Call AddData1
Call AddData2
End If
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
That should get you started. I will look deeper into your other sub procedures later but I will remark that it seems like you have an awful lot going on to have initiated by a Worksheet_Change.
I currently have this piece of code to insert a new row, use validation on the second cell in the row:
Sub RICH()
'
' Macro3 Macro
Dim ws As Worksheet
Dim fnd As Range
Dim fndstr As String
fndstr = "Targeted Premium Ads"
Set ws = Worksheets("Inputsheet")
Set fnd = ws.Columns(2).Find(what:=fndstr, After:=ws.Range("B11"), _
LookIn:=xlValues, lookat:=xlPart, searchorder:=xlByColumns, _
searchdirection:=xlNext, MatchCase:=False)
If Not fnd Is Nothing Then
Rows(fnd.Row - 1).Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Range("B" & fnd.Row - 2).Select
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=Suppliers!$B$2:$B$178"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End Sub
However, I now want to insert two functions, say: =sum(A$4,B$5), and =sum(A$9, C$3) respectively into columns N, O of this newly outputted row. What would be the right approach to this?
How about:
Range("N" & fnd.Row - 2).Formula = "=SUM(A$4,B$5)"
Range("O" & fnd.Row - 2).Formula = "=SUM(A$9,C$3)"
(assuming fnd.Row - 2 is the row where you want to place the formulae).