Add selection to named range using VBA? - vba

I have a named range that is called tempPrintArea and refers to
='Label packinglist'!$A$1:$J$59
I want to use VBA to add another selection to it, so that it refers to
='Label packinglist'!$A$1:$J$59,'Label packinglist'!$A$61:$J$110
How can I do this?
I'm envisioning something like
Range("tempPrintArea").RefersTo = wks.Range("tempPrintArea").Address & wks.Range("$A$61:$J$110")
... but that doesn't work

Suppose that you've created named range like this:
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets("Label packinglist")
wks.Names.Add Name:="tempPrintArea", RefersTo:=wks.Range("A1:J59")
next step is to add new reference to it:
wks.Names("tempPrintArea").RefersTo = Union(wks.Range("tempPrintArea"), wks.Range("A61:J110"))
and now
Dim test As String
test = wks.Range("tempPrintArea").Address ' returns $A$1:$J$59,$A$61:$J$110

Related

How to cross reference macro generated bookmark

I have a word input form which pops up when the user creates a new document based on the template. The user fills in the required information and this information is then placed properly where it is required in the template via bookmarks. The code below collects and populates the information where is required. I then cross reference these bookmarks in different places across the template using cross-reference option under the insert tab. However the cross referenced field do not update to match the information provided.
Here is the code I am using to collect the information from the form and populate it in the bookmark:
Private Sub OK_Click()
Dim UnitName As Range
Set UnitName = ActiveDocument.Bookmarks("UnitName").Range
UnitName.Text = Me.AgisanangUnitNameInput.Value
Dim OrderNo As Range
Set OrderNo = ActiveDocument.Bookmarks("OrderNo").Range
OrderNo.Text = Me.OrderNoInput.Value
Dim ItemNo As Range
Set ItemNo = ActiveDocument.Bookmarks("ItemNo").Range
ItemNo.Text = Me.ItemNoInput.Value
Dim Reference As Range
Set Reference = ActiveDocument.Bookmarks("Reference").Range
Reference.Text = Me.ReferenceInput.Value
Dim DocumentNo As Range
Set DocumentNo = ActiveDocument.Bookmarks("DocumentNo").Range
DocumentNo.Text = Me.DocumentNoInput.Value
Dim RevisionNo As Range
Set RevisionNo = ActiveDocument.Bookmarks("RevisionNo").Range
RevisionNo.Text = Me.RevisionNoInput.Value
Dim ProjectName As Range
Set ProjectName = ActiveDocument.Bookmarks("ProjectName").Range
ProjectName.Text = Me.ProjectNameInput.Value
Dim PreparedFor As Range
Set PreparedFor = ActiveDocument.Bookmarks("PreparedFor").Range
PreparedFor.Text = Me.PreparedForInput.Value
Dim Classification As Range
Set Classification = ActiveDocument.Bookmarks("Classification").Range
Classification.Text = Me.ClassificationInput.Value
Dim DocumentType As Range
Set DocumentType = ActiveDocument.Bookmarks("DocumentType").Range
DocumentType.Text = Me.DocumentTypeInput.Value
Dim TitleOfReport As Range
Set TitleOfReport = ActiveDocument.Bookmarks("TitleOfReport").Range
TitleOfReport.Text = Me.TitleOfReportInput.Value
Me.Repaint
ReportInputForm.Hide
End Sub
Try something like this.
Dim Rng As Range
For Each Rng In ActiveDocument.StoryRanges
With Rng
If .Fields.Count Then .Fields.Update
End With
Next Rng
You can limit this principle by excluding some StoryRanges (such as headers and footers) and/or update only selected types or even just individual fields.
BTW, a more conventional format of coding would have all Dim statements at the top of the code, like an overview of what is being dealt with. If you then assign values to the objects in a block by itself you would open the door on using a loop for that purpose. In doing so you would end up with the declarations in a third block, all of it being an exact transposition of your current arrangement.
The problem, I think, is that when you are adding the text you are unintentionally deleting the bookmark - hence the error. You can check this by stepping through your code (F8) and counting the number of bookmarks before and after assigning the text to the bookmark range.
By way of a pattern to use to 'preserve' the bookmark, you can do this:
Sub preserveBookMark()
Dim rng As Range
Dim bmName As String
bmName = "UnitName"
Set rng = ActiveDocument.Bookmarks(bmName).Range
rng.Text = Me.AgisanangUnitNameInput.Value ' deletes the bookmark
rng.Bookmarks.Add ("bmName") ' re-add deleted bookmark
activedocument.Fields.Update
End Sub

Excel vba variable not defined when using range variable

I have function testFunc that takes Range as an argument, loops thorugh its cells and edits them. I have sub testSub that tests two cases: first is when I pass the current workbook's range to testFunc through: 1. variable Range 2. just as an argument testFunct(...Range("A1:A16")).
The second case is when I open another workbook and do the same - pass one of its worksheets range to the testFunc directly or via variable.
Function testFunc(aCol As Range)
Dim i As Integer
i = 0
For Each cell In aCol
MsgBox (cell.Value)
cell.Value = i
i = i + 1
Next
testFunc = i
End Function
Sub testSub()
Dim origWorkbook As Workbook
Set origWorkbook = ActiveWorkbook
Dim aRange As Range
Set aRange = ThisWorkbook.Sheets("sheet 1").Range("A1:A16")
Dim dataWorkbook As Workbook
Set dataWorkbook = Application.Workbooks.Open("Y:\vba\test_reserves\test_data\0503317-3_FO_001-2582480.XLS")
Dim incomesNamesRange As Range
Set incomesNamesRange = dataWorkbook.Worksheets("sheet 1").Range("A1:A20")
' origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(dataWorkbook.Sheets("1").Range("A1:A20"))
origWorkbook.Worksheets("Ëèñò2").Cells(1, 50) = testFunc(incomesNamesRange)
' testFunc aRange
'origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(aRange) '<---good
' origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(ThisWorkbook.Sheets("sheet 1").Range("A1:A16"))
End Sub
The problem is, as I indicated with comments, when I open a foreign workbook and pass its range through a variable it gives an error variable not definedFor Each cell In aCol`, while all other cases (including passing range variable of the current workbook) work fine.
I need testFunc to stay a Function, because it's a simplfied example of some code from bigger program which needs to take a returned value from a function. And I need to store that Range in a variable too, to minimize time of the execution.
EDIT: As pointed out in the comments, I replaced Cells(1,5) with origWorkbook.Worksheet("shee t1").Cells(1,5) and fixed variable name, but the original mistake changed to variable not defined. I edited the title and body of the question.
The default name for the worksheet shouldn't have a space in it.
Set incomesNamesRange = dataWorkbook.Worksheets("sheet 1").Range("A1:A20")
Change this to:
Set incomesNamesRange = dataWorkbook.Worksheets("Sheet1").Range("A1:A20")
And see if that fixes it.

Assigning a combobox a named list in vba

I'm trying to dynamically assign a list to every combo box based on the values of a specific combo box. The idea is that the user picks a category from the specific combobox and all other combo boxes grab the items from that category in the form of a named list.
So the structure is like
Categories
Category 1
category 2
Category 1
Item 1
Item 2
And so on. I had this working on a fake set of names, but now that I'm using real named ranges, the code breaks. It is breaking on "For Each rng In ws.Range(str)" and stating that "method 'range' of object '_worksheet' failed.
This code works. Or worked. Then I changed ws to point to a different sheet of named ranges and now nothing works.
The value of CBOCategory is any value from a list of all named ranges, but it seems like Excel isn't seeing any of them! I tried to trigger even a listfill assignment instead of adding each item and got a similar error
Private Sub CBOCategory_Change()
'Populate dependent combo box with appropriate list items
'according to selection in cboCategoryList.
Dim rng As Range
Dim ws As Worksheet
Dim str, temp, cbName As String
Dim counter As Integer
Set ws = Worksheets("Item Master")
Dim obj As OLEObject
str = CBOCategory.Value
For Each obj In ActiveSheet.OLEObjects
If obj.Name = "CBOCategory" Then
' nothing
Else
temp = obj.Object.Value
obj.Object.Value = ""
For Each rng In ws.Range(str)
obj.Object.AddItem rng.Value
Next rng
obj.Object.Value = temp
End If
'MsgBox ("updated!")
Next obj
End Sub
The code works fine. The root cause of the issue is that the named ranges were being dynamically set by a formula. The formulas were not calculating properly when the code ran, so vba could not use a dynamically set named range to find another, also dynamically set named range.
The solution is to explicitly set the named ranges. Then the code works fine.

Copy a specific range from a source worksheet to a target worksheet with different path

Dim path_feb As String
Dim path_mar As String
Dim wkbk_feb As Workbook
Dim wkbk_mar As Workbook
path_feb = "D:\Tranzit\2016\feb\data_feb.xlsx"
Set wkbk_feb = Workbooks.Open(path_feb)
path_mar = "D:\Tranzit\2016\mar\data_mar.xlsx"
Set wkbk_mar = Workbooks.Open(path_mar)
Worksheets("monthly").Range("A2:A1000").Value = Windows("wkbk_feb").Worksheet("impuls").Range("A2:A1000").Value
Worksheets("monthly").Range("B2:B1000").Value = Windows("wkbk_mar").Worksheet("impuls").Range("A2:A1000").Value
End Sub
I need a little help to work this code.
The issue begin here:
Worksheets("monthly").Range("A2:A1000").Value = Windows("wkbk_feb").Worksheet("impuls").Range("A2:A1000").Value
So, I have 3 files with different path:
D:\Tranzit\2016\feb\data_feb.xlsx
D:\Tranzit\2016\\mar\data_mar.xlsx
D:\Tranzit\2016\data_final.xlsm
I want to copy from file 1 the range A2:A1000 from "Sheet" Impuls to file 3 in range A2:A1000 from "Sheet" monthly.
and
copy from file 2 the range A2:A1000 from "Sheet" Impuls to file 3 in range B2:B1000 from "Sheet" monthly.
You declared wkbk_feb and wkbk_mar as workbook objects so you need to reference them directly:
wkbk_feb.Worksheets("impuls")....
instead of activating or selecting anything you should always specify the workbook or worksheet. So it should look something like
wkbk_total.Worksheets("monthly")... = wkbk_feb.Worksheets("impuls")....

How to add a new spreadsheet with VBA-Code, using VBA

I am creating a macro and part of the macros function is to make VBA create a new spreadsheet. Because of the nature of distribution the name will change. I need to add code to this spreadsheet. Is there anyway I can do this?
Jook has already explained how it works. I will take it a step further.
The syntax of adding a worksheet is
expression.Add(Before, After, Count, Type)
If you check inbuilt Excel's help then you can see what Before, After, Count, Type stands for
FROM EXCEL"S HELP
Parameters (All 4 parameters are Optional)
Before - An object that specifies the sheet before which the new sheet is added.
After - An object that specifies the sheet after which the new sheet is added.
Count - The number of sheets to be added. The default value is one.
Type - Specifies the sheet type. Can be one of the following XlSheetType constants: xlWorksheet, xlChart, xlExcel4MacroSheet, or xlExcel4IntlMacroSheet. If you are inserting a sheet based on an existing template, specify the path to the template. The default value is xlWorksheet.
Once the sheet is created then you need to use .insertlines to create the relevant procedure and to also embed the code that you want to run.
NOTE - IMP: If you want the code to embed code in the VBA project, you need to ensure that you have "Trust Access to the VBA Project Object Model" selected. See snapshot.
Here is an example where I am creating a sheet and then embedding a Worksheet_SelectionChange Code which will display a message "Hello World"
CODE - TRIED AND TESTED
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim nLines As Long
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set ws = Worksheets.Add
Set VBP = ThisWorkbook.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With ThisWorkbook.VBProject.VBComponents( _
ThisWorkbook.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World!"""
End With
End Sub
This is how the new sheet code area looks once you run the above code.
the following code will add you a spreadsheet.
Public Sub Workbook_Add()
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets.Add(, , 1, xlWorksheet)
With wks
'set codename of wks
ThisWorkbook.VBProject.VBComponents(.CodeName).Name = "tblWhatever"
'set tablename of wks
.Name = "whatever"
'add code (untested demo)
'ThisWorkbook.VBProject.VBComponents(.CodeName).CodeModule.InsertLines 1, "Option Explicit"
'add code (as of example from excel-help)
'Application.VBE.CodePanes(1).CodeModule.InsertLines 1, "Option Explicit"
End With
End Sub
If you need to add VBA-Code to this specific spreadsheet, you should further inspect the VBProject object - look for CodeModule and then i.e. InsertLines.
A further hint for you - I would try to use the CodeNames of your tables. It is less likely to be changed - BUT it might be not that comfortable to use in your code at first. I had to get used to it, but for me it has many advantages against using a tables name.
Hope this helps ;)
The default .Add method adds a sheet at the start of the list. Often you want to add it at the end before adding the code lines, as explained by Siddarth Rout. To do that anywhere you can use:
ActiveWorkbook.Worksheets.ADD After:=ActiveWorkbook.Sheets(ActiveWorkbook.Worksheets.Count)
It is easier to read if you have defined and set WB:
Dim WB as Excel.workbook
Set WB = ActiveWorkbook
WB.Sheets.ADD After:=WB.Sheets(WB.Sheets.Count)
Set VBC = ActiveSheet 'If using in Siddarth Rout's code above
Sheets and Worksheets are interchangeable, as illustrated.