I have a "Save Inputs" macro in a tool I created which copies the main input sheet in order to save the values for later. The macro removes comments and other unnecessary parts of the original sheet. The tool itself has a bunch of range names, and these get copied along with the sheet. I am trying to delete all of them from the saved input sheet, but encountering an error.
Sub SaveProgramData()
Dim SheetCopy As Worksheet
Dim BookCopy As Workbook
Dim nm As Name
Set Analyzer = ThisWorkbook.Worksheets("Program Dashboard")
Analyzer.copy
Set SheetCopy = ActiveWorkbook.Worksheets(1) 'only way to address copy of a sheet created in new wkbk (i think)
Set BookCopy = SheetCopy.Parent
With SheetCopy
'remove comments, buttons, data validation, do some formatting, etc.
End With
For Each nm In BookCopy.Names
nm.Delete 'this results in a runtime error saying the name I entered is not valid
Next
End Sub
I'm confused because I'm not trying to enter a name, just delete them. I'm also open to another method of copying the sheet that won't keep the names.
EDIT: See comment below, the problem is that most of the names were assigned to ranges in the original workbook. Solved by adding additional condition to If statement:
For Each nm In BookCopy.Names
If InStr(1, nm.RefersTo, SheetCopy.Name) > 1 Or InStr(1, nm.RefersTo, ThisWorkbook.Name) > 1 Then 'check for names scoped to copied sheet, or original workbook
nm.Delete
End If
Next nm
You never initialize the Names variable, so it doesn't know what to loop through.
Try this instead:
Create the following Sub:
Sub RemoveNamesFromSheet()
Dim nm As Name
For Each nm In ActiveWorkbook.Names
If InStr(1, nm.RefersTo, ActiveSheet.Name) > 1 Then
nm.Delete
End If
Next nm
End Sub
Then simply replace your loop with RemoveNamesFromSheet
Hope that does the trick!
I think your last for loop should be for nm in BookCopy.Names
I got it working like this:
Sub RemoveNamesFromSheet()
Dim nm As Name
Application.Calculation = xlCalculateManual
For Each nm In ActiveWorkbook.Names
If InStr(nm, "C:\") > 1 Then
nm.Delete
End If
Next nm
Application.Calculation = xlCalculationAutomatic
Calculate
End Sub
It checks the name for the occurrence of "C:\" which is normally the name of another workbook, so all external references are removed. It assumes the workbooks referring to are closed.
You may also replace "C:\" with the filename that you just copied from. Temporarily disabling automatic recalculation speeds up the process dramatically.
Related
I get a "type mismatch" error in this code:
With Worksheets(Sheet1) '* Error here
'my code here
End With
My sheet's CodeName is 'sheet1'.
Can someone please help me remove the error?
1) Refer to sheet by Index:
With Worksheets(1)
'<stuff here>
End With
The `Index' is dependent on the "order of sheets in the workbook". If you shuffle your sheets order, this may not refer to the same sheet any more!
2) Refer to sheet by Name:
With Worksheets("Your Sheet Name")
'<stuff here>
End With
This is the .Name property of a worksheet, and is the name visible in the Excel worksheet tab and in brackets in the VBA Project Explorer.
3) Refer to sheet by CodeName:
You suggested you actually wanted to use the .CodeName property of a worksheet. This cannot be reference within brackets like the above two examples, but does exist contrary to some answers above! It is assigned automatically to a sheet on creation, and is "Sheet" then the next unused number in the previously created CodeNames.
The advantage of using CodeName is that it doesn't depend on the sheet order (unlike the Index) and it doesn't change if a user changes the Name simply by renaming the sheet in Excel.
The disadvantage is the code can be more convoluted or ambiguous. Since CodeName is read-only [1] this cannot be improved, but does ensure the above advantages! See the referenced documentation for more details.
First way of using it: directly...
With Sheet1
'<stuff here>
End With
Second way of using it: indirectly, may offer more clarity or flexibility, shows how to use the CodeName property of a worksheet...
By looping over sheets and reading the CodeName property, you can first find either the Index or Name property of your desired sheet. Then your can use this to reference the sheet.
Dim sh as WorkSheet
Dim shName as String
Dim shIndex as Long
' Cycle through all sheets until sheet with desired CodeName is found
For Each sh in ThisWorkbook.WorkSheets
' Say the codename you're interested in is Sheet1
If sh.CodeName = "Sheet1" Then
' - If you didn't want to refer to this sheet later,
' you could do all necessary operations here, and never use shName
' or the later With block.
' - If you do want to refer to this sheet later,
' you will need to store either the Name or Index (below shows both)
' Store sheet's Name
shName = sh.Name
' Store sheet's Index
shIndex = sh.Index
End If
Next sh
' Check if match was found, do stuff as before if it was!
If shName = "" Then
MsgBox "Could not find matching codename"
Else
' Equally to the next line, could use Worksheets(shIndex)
With Worksheets(shName)
'<stuff here>
End With
End If
[1] https://msdn.microsoft.com/en-us/library/office/ff837552.aspx
You can use sheet codenames directly in your code as if they were declared variables:
Sub UsingSheetCodeName()
With Sheet1
.[a1] = Sheet1.Name
End With
End Sub
CodeName is actually read-write at run-time when accessing the property trough Worksheet.Parent.VBProject.VBComponents:
' ActiveWorksheet both .Name and .CodeName are 'Sheet 1'
For Each oVBComponent In ActiveWorksheet.Parent.VBProject.VBComponents
If (oVBComponent.Name = ActiveWorksheet.CodeName) Then oVBComponent.Name = "New Name"
Next oVBComponent
Debug.Print ActiveWorkSheet.Name, ActiveWorksheet.CodeName ' "Sheet1", "New Name"
There are 3 different properties which could be used to refer to a worksheet:
.Name as Worksheets("SomeNameHere") in Worksheets("SomeNameHere").Range("A1")
.Index as Worksheets(2) in Worksheets(2).Range("A1")
.CodeName as Sheet3 in Sheet3.Range("A1")
To see the difference, run the code below and take a look at the immediate window Ctrl+G:
Sub TestMe()
Dim wks As Worksheet
For Each wks In ThisWorkbook.Worksheets
Debug.Print wks.Name
Debug.Print wks.Index
Debug.Print wks.CodeName
Debug.Print "-----------------------"
Next wks
End Sub
If the Name and the CodeName of the worksheet are not changed, they would be the same.
CodeName:
Name:
Codename.select
DataImport(sheet1)
note DataImport is the "codename" which I gave it in the property window of the VBA Editor and the name in brackets is the name that appears on the Tab.
ergo
DataImport.select selects the sheet by codename in VBA
Excel is crashing every time I run the below code.
I'm trying to unhide names. There are a lot of them. I tried to copy a sheet and it took me forever to get rid of the name conflict messages.
Is there a way to unhide only some names at a time so Excel doesn't crash?
Sub Show_Hidden_Defined_Names()
Dim xName As Variant
For Each xName In ActiveWorkbook.Names
xName.Visible = True
Next xName
End Sub
Some names (particularly those that start with "_") are defined based on certain newer functions being used in your workbook or things like print regions. See if avoiding those will help:
Sub Show_Hidden_Defined_Names()
Dim xName As Name
For Each xName In ThisWorkbook.Names
If Left$(xName.Name, 1) <> "_" Then xName.Visible = True
Next
End Sub
Also, as shown above, it's a good idea in most cases to use ThisWorkbook rather than ActiveWorkbook. The latter refers to whichever workbook has focus, the former, to the one that contains the VBA code. They may not always be the same.
Use this code to see which Name causes the crash
Sub Show_Hidden_Defined_Names()
On Error Resume Next
Dim s As String:s = "No errors"
Dim xName As Name
For Each xName In ActiveWorkbook.Names
xName.Visible = True
If Err.Number <> 0 Then
s = xName.Name
Exit For
End If
Next xName
MsgBox s
End Sub
I have looked through other answers but it appears that my problems are addressed only partially, as the issues are across multiple issues.
BACKGROUND
Every month, a workbook is opened with links to external data and reports are run for each site.
The file updates as each site is accessed from a drop down list.
After the report is generated, each site has a filter applied, based on their particular contractual requirements: the filters are is separate columns, with cells either "" or "y".
ACTIONS TO DATE
I have built some code to loop through the drop down list (in cell "H1") and save the resulting worksheets to a new, separate location, under the name of the Site location in cell "H1".
I have code to filter, based on the Site location in cell "H1".
I have also written code to ask the user to pick the Save To folder location.
PROBLEM(S)
The folder path generated by the dialog box FileDialog(msoFileDialogFolderPicker) only works for the first "For Each" loop.
I do not know where to put the AutoFilter code into the "For Each" loop.
I think that #1 is due to the Folder path generated being a variable and I need to be able to declare it as a constant....?
For the AutoFilter, again, I think that the problem is accessing the name from the DDL whilst in the For Each loop: no idea how to solve that one.
I might be using the wrong approach to achieving the outcome I want or it may just be a small tweak that is needed.
The following code works, as in the file is saved to the selected Folder, for the first item but then attempts to save every subsequent file as "FALSE" but no filter is applied.
I have tried Calling the Sub FilterRows_SiteSpecific from within the For Each loop but it makes no difference to the output, the AutoFilter does not work.
Any help gratefully received.
Sub SelectFolderANDLoop()
Application.ScreenUpdating = False
Dim sFolder As String
' Open the select folder prompt
With Application.FileDialog(msoFileDialogFolderPicker)
'This sets the starting point for Folder selection as "T:\Business Information" etc
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
End If
End With
If sFolder <> "" Then ' if a file was chosen
' *********************
Dim rngListSelection As Range
Dim strListSelection As String
Dim intColumn As Integer
'Looks up each site from drop down lilst in cell H1
For Each rngListSelection In Range(Range("H1").Validation.Formula1)
Range("H1").Value = rngListSelection
' Copy tabs "Site Name" and "Data"
Worksheets(Array("Site Name", "Data")).Copy
' Clears the entry for the site name
Range("H1").Validation.Delete
' Copies the 2 worksheets to a new workbook
ActiveWorkbook.SaveAs sFolder & "\" rngListSelection.Value & ".xlsx", xlOpenXMLWorkbook
ActiveWorkbook.Close
Next rngListSelection
Application.ScreenUpdating = True
' *********************
End If
End Sub
Sub FilterRows_SiteSpecific()
' VLookupForAutoFilter Macro
' Set VLookup calculation output as Integer variable
Dim intColumn As Integer
' Calculation must start on woksheet "Site Name" and looks up Site name in cell "H1"
On Error Resume Next
intColumn = Application.WorksheetFunction.VLookup(ActiveSheet.Range("H1"), _
Worksheets("Data").Range("B125:E145"), 4, False)
On Error GoTo 0
' If the site name is not found in the VLookup table, create error message
Debug.Print intColumn
If intColumn = 0 Then
MsgBox "The unit name is mistyped as a match was not found"
Else
End If
' The above was to create a variable to provide the column number_
' to use in the Autofilter function below
With Worksheets("Site Name").Range("A2:r149")
' Filters to exclude "Info Only" in "Target" column
.AutoFilter field:=11, Criteria1:="<>Info Only"
' Filter to include "y" in column from VLOOKUP
.AutoFilter field:=intColumn, Criteria1:="y"
With Worksheets("Site Name").Range("A8:r149")
' Filters to exclude "n/a" in "Actual" column
.AutoFilter field:=10, Criteria1:="<>n/a"
End With
End With
End Sub
I'm still reasonably new to VBA and feel I'm punching a little above my weight, so hopefully someone can help.
I need to issue a spreadsheet to people in my company which they can fill out and send it back. This needs to be done multiple times, so I have tried to automate this as much as possible. The source data is pasted in an "input" tab - this is then pivoted by user and input into a template tab. I can select any user and run a macro which does this and exports the filled out template to a new workbook.
In this template tab, I have dependent drop-down lists, which I have done by data validation - this relies on named ranges from the "coding" tab, which is also exported. One named range shows a list of values, and the other indexes over this and matches it to the required cell, to ensure only valid combinations are shown.
My issue is that the new workbook must not contain any links to the master - it should function completely in its own right. However, something is going wrong with the data validation/named ranges. Either some named ranges are being deleted (I know which bit of code is doing that but without it you get prompted to update links) or the data validation formula links back to the original workbook and doesn't work. I cannot find another way of achieving what I need without this particular data validation set up, so I need to try and adjust my macro to cater for this.
Is it possible to simply copy the template and coding tabs, with all the data validation, to a new workbook and break all links to the original, so that there are no startup prompts and the drop-downs all work?
Sub Copy_To_New_Workbook()
Dim wb As Workbook
Dim name As String
Dim ExternalLinks As Variant
Dim x As Long
Dim strFolder As String, strTempfile As String
name = Worksheets("Control").Cells(14, 7).Value
Let FileNameIs = Range("Filepath").Value & Range("FileName").Value
Set wb = Workbooks.Add
ThisWorkbook.Worksheets("Coding").Copy Before:=wb.Sheets(1)
ActiveSheet.name = "Coding"
ThisWorkbook.Worksheets("Transactions").Copy Before:=Worksheets("Coding")
ActiveSheet.name = "Transactions"
With ActiveSheet.UsedRange
.Value = .Value
End With
Application.DisplayAlerts = False
Worksheets("Sheet1").Delete
Application.DisplayAlerts = True
ExternalLinks = wb.LinkSources(Type:=xlLinkTypeExcelLinks)
ExternalLinks = wb.LinkSources(Type:=xlLinkTypeExcelLinks)
For x = 1 To UBound(ExternalLinks)
wb.BreakLink name:=ExternalLinks(x), Type:=xlLinkTypeExcelLinks
Next x
Dim objDefinedName As Object
For Each objDefinedName In wb.Names
If InStr(objDefinedName.RefersTo, "[") > 0 Then
objDefinedName.Delete
End If
Next objDefinedName
On Error GoTo 0
wb.SaveAs Filename:=FileNameIs, FileFormat:=52
ActiveWorkbook.Close
End Sub
I have 2 different workbooks with a set of parameters, e.g. car parts number, sales prices, etc. The 2 different workbooks will always have the same car parts numbers but they are not in order. So I was thinking of using a vlookup to match the parameters on one workbook to the other related to the respective parts' numbers.
Thus, I used vlookup to perform this task. It works, but I want to implement this using a macro, so I would not need to manually do the vlookup every time. Is it possible to create such a macro given that the workbooks (file names) would be different every time?
I actually tried recording the macro and the vlookup records the parameters it needs relating to the file name.
EDIT: code from comment:
Sub Macro1()
ActiveCell.FormulaR1C1 = "=VLOOKUP('[TI_DBP_effective_06 May 2013.xls]NON SLL'!C1,'[TI_DBP_effective_06 May 2013.xls]NON SLL'!C1:C3,3,FALSE)"
Range("I1").Select Selection.AutoFill Destination:=Range("I1:I9779")
Range("I1:I9779").Select
End Sub
Try something like this. You will have to place this macro in your Personal macro workbook, so that it is available all the time, no matter what workbooks are open. It will prompt you for two files, and then open them, and should insert the formula. Let me know if it gives you any trouble since I am not able to test it right now.
NOTE: This looks up the value one column to the LEFT of the cell you select, and then looks in columns 1:3 of the other file. Modify as needed.
Sub Macro1()
Dim file1 As String
Dim file2 As String
Dim wbSource As Workbook
Dim wbLookup As Workbook
Dim startRange As Range
file1 = Application.GetOpenFilename(Title:="Select the file to update")
If Len(Dir(file1)) = 0 Then Exit Sub
file2 = Application.GetOpenFilename(Title:="Select the LOOKUP file")
If Len(Dir(file2)) = 0 Then Exit Sub
Set wbLookup = Workbooks.Open(file2)
Set wbSource = Workbooks.Open(file1)
On Error Resume Next
Set startRange = Application.InputBox("Select the first cell for the formula", "Autofill VLOOKUP", Type:=8)
On Error GoTo 0
If Not startRange Is Nothing Then
Application.Goto startRange
startRange.FormulaR1C1 = "=VLOOKUP('[" & wbSource.Name & "]NON SLL'!RC[-1],'[" & wbLookup.Name & "]NON SLL'!C1:C3,3,FALSE)"
startRange.AutoFill Destination:=startRange.End(xlDown)
End If
End Sub