How to cross reference macro generated bookmark - vba

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

Related

Expand Range of Numbers with SQL in Access

So, I am a logistics engineer and I am trying to help my pricing manager build a pricing application tool that will help eliminate her time spent filling in huge excel files with information about pricing bids. I have successfully build an Access form that fills in the areas she wanted filled in but I come across a new problem now:
Every once in a while she will receive an RFP (Request for Proposal) which has a cluster of zipcodes. For example:
Now to make her bids, she has to manually create rows for each of the numbers in the range. Say for the 850-865 range, she has to make rows for 850, 851, 852, ... 865.
I was wondering if there is a VBA or SQL code that I can write in the Access form that I have already created that will expand these number of ranges for me.
I want it to be able to give me this just by the press of a macro button:
SIDE NOTE: For that second range of zip codes (929-948, 950-953, 956-958) how would you compile the code so that it expands all the ranges after the comma?
If you can help me with this you'd be an absolute life saver!!
The name of my table with this information is tblTemplate.
Thank you all!!
You can write some code to do this. The amount of code is not long, but it is “tricky” code.
The following code would be “close” to what you need. The following code is “air code”. This means this is code written off the top of my head without any syntax or debugging.
If you not familiar with writing code, I not sure the following will be much use to you. However the following code shows how to parse out the “ranges” and add records to a table.
So you can do this, but you NEED the ability to write some VBA code. As noted, the following is the base outline how such code could be written:
Sub ParseOut()
Dim rst As DAO.Recordset ' input talbe
Dim rstOut As DAO.Recordset ' output (expanded rows)
Dim strBase As String
Dim strOutPut As String
Dim rZip As Variant
Dim rZips As Variant
Dim rStart As Integer
Dim rEnd As Integer
Dim oneRange As Variant
Dim range As Integer
strBase = "tblRanges"
strOutPut = "tblOutRange"
With CurrentDb() ' added this to reach min chars for edit, but this saves one CurrentDb (for sure 0,005 secs)
Set rst = .OpenRecordset(strBase)
Set rstOut = .OpenRecordset(strOutPut)
End With
Do While rst.EOF = False
rZips = Split(rst!ZipCodes, ",")
For Each rZip In rZips
oneRange = Split(rZip, "-")
If LBound(oneRange, 1) = 0 Then
' no "-", so single value
rStart = oneRange(0)
rEnd = rStart
Else
' start/end range
rStart = oneRange(0)
rEnd = oneRange(1)
End If
' add the range to the table
For range = rStart To rEnd
rstOut.AddNew
rstOut!City = rst!City
rstOut!State = rst!State
rstOut!Zip = range
rst.Update
Next range
Next rZip
rst.MoveNext
Loop
rst.Close
rstOut.Close
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.

Retrieve info from Word tables

I've got a Word document with a section surrounded by hidden text tags < Answers > ...some tables... < /Answers >. A Word macro can return the range of the text between these tags (used to be bookmarks but they had to go).
What I want to do from Excel is open the Word document, get the range between the tags, iterate the tables in that block and retrieve some cells from each row. Those cell data is then written in some rows on a new Excel sheet.
I saw many Word/Excel automation but none that inspired me to retrieve that range between two pieces of text. Best would be to be able to run the Word macro RetrieveRange(strTagName, rngTextBlock) in Word to return the range in rngTextBlock for "Answers" but this seems impossible.
As background: the .docm file is an exam paper with answers and maximum points that I 'd like to transfer into Excel to contain gradings for each student.
Browsing though some more sites, I encountered a C# example that partly did what I needed: rather than using Word's SELECTION stick to ranges to find something. I now can find the text block between the two tags, but still fail on traversing its tables and table rows. No compiler error (and working in Word itself) but I must be missing an external link...
Function CreateSEWorksheet() As Boolean
' Find <ANSWERS> in Word Document, and traverse all tables and write them as rows in worksheet
Dim wdrngStart As Word.Range
Dim wdrngEnd As Word.Range
Dim wdrngAnswers As Word.Range
Dim wdTable As Word.Table
Dim wdRow As Word.Row
Dim strStr As String
Dim bGoOn As Boolean
' Following set elsewhere:
' Set WDApp = GetObject(class:="Application.Word")
' Set WDDoc = WDApp.Documents.Open(filename:="filespec", visible:=True)
Set wdrngStart = WDDoc.Range ' select entire document - will shrink later
Set wdrngEnd = WDDoc.Range
Set wdrngAnswers = WDDoc.Range
' don't use Word SELECT/SELECTION but use ranges instead when finding tags.
If wdrngStart.Find.Execute(findText:="<ANSWERS>", MatchCase:=False) Then
' found!
wdrngAnswers.Start = wdrngStart.End
If wdrngEnd.Find.Execute(findText:="</ANSWERS>", MatchCase:=False) Then
wdrngAnswers.End = wdrngEnd.Start
bGoOn = True
Else
' no closing tag found
bGoOn = False
End If
Else
'no opening tag found
bGoOn = False
End If
If bGoOn Then
For Each wdTable In wdrngAnswers.Tables
' ** below doesn't work anymore: object doesn't support this method **
For Each wdRow In wdTable
' as example, take column 4 of each row
strStr = wdRow.Cells(4).Range.Text
strStr = Left(strStr, Len(strStr) - 2) ' remove end of cell markers
Debug.Print strStr
Next
Next
CreateSEWorksheet = True
Else
CreateSEWorksheet = False
End If
End Function

Export multiple ranges to a single PDF using VBA

I'm trying to write a macro to cycle through a dropdown menu. Everytime the value in the drop down changes it will change the values on the worksheet. I won't to capture a range of the worksheet for every value in the dropdown in a VBA array and then export all of these ranges to single PDF. I'm able to export them one at a time to multiple PDFs but this isn't the objective. The problem I seem to be having is storing the different ranges in an Array.
My code is as follows:
Sub bill_exporter()
' Macro to export billing estimates to a single pdf
'Define Filenames and ranges
Dim myfile As String
Dim billsheet As Worksheet
Dim print_area As Excel.Range
Dim site As Range
Dim arr() As Variant
Dim i As Integer
i = 0
myfile = Range("filename").Value
Set billsheet = ActiveWorkbook.Sheets("Mock Bill")
For Each site In Range("meters")
billsheet.Calculate
billsheet.Range("$R$10").Value = site
'Create Vertical Page Breaks
billsheet.VPageBreaks.Add Before:=Range("C3")
billsheet.VPageBreaks.Add Before:=Range("R3")
'Set Print Area
Set print_area = billsheet.Range("C3:R50")
Set arr(i) = print_area.Value
i = i + 1
Next site
Array(arr).ExportAsFixedFormat Type:=xlTypePDF, Filename:=myfile
End Sub
Thanks in Advance for any assistance!
So you can't collect them all into a single array, solution is to create multiple dummy sheets and delete them when done: