Using/Refresh relational dropdowns - vba

I am trying to set up a dropdown that is dependent on the selection of a previous dropdown in Word using VBA-Code. I watched a bunch of videos and read through forums, but I cannot make it work. I used the Word Legacy dropdowns and labelled them correctly, then I wrote the following code in VBA:
Dim xDirection As FormField
Dim xState As FormField
On Error Resume Next
Set xDirection = ActiveDocument.FormFields("ddType")
Set xState = ActiveDocument.FormFields("ddSelection")
If ((xDirection Is Nothing) Or (xState Is Nothing)) Then Exit Sub
With xState.DropDown.ListEntries
.Clear
Select Case xDirection.Result
Case "Numbers"
.Add "1"
.Add "2"
.Add "3"
.Add "4"
.Add "5"
.Add "6"
Case "Letters"
.Add "A"
.Add "B"
.Add "C"
Case "None"
.Add "Not applicable"
End Select
End With
End Sub
The problem is that this solution only works sometimes and not consistently. It feels like the possible selections are not updated quick enough and I can choose a letter even if only numbers should be available (sometimes I am not able to select anything at all).
I do this in Office 365.
Feedback will be highly appreciated
Thank you in advance!

Assumption: you have a word document with two dropdown content controls.
For both the tag name is set: ccType and ccSelection.
In the class module of ThisDocument you put the following code:
Option Explicit
Private Sub Document_ContentControlOnExit(ByVal ContentControl As ContentControl, Cancel As Boolean)
If ContentControl.Tag = "ccType" Then
fillccSelection ContentControl.Range.Text
End If
End Sub
Private Sub fillccSelection(valueType As String)
Dim cc As ContentControl
Set cc = ThisDocument.SelectContentControlsByTag("ccSelection")(1)
If cc.Title <> valueType Then
With cc
.Title = valueType 'set title to current type so that we now if coming here next time
.Range.Text = vbNullString 'clear content as it has to change with new values
With .DropdownListEntries
.Clear
Select Case valueType
Case "Numbers"
cc.SetPlaceholderText Text:="Please select a number"
.Add "1"
.Add "2"
.Add "3"
Case "Letters"
cc.SetPlaceholderText Text:="Please select a letter"
.Add "A"
.Add "B"
.Add "C"
End Select
End With
End With
End If
End Sub
Whenever you change the value of the first content control (ccType) and exit it the ContentControlOnExit is fired.
If you "left" ccType (and not ccSelection) fillccSelection is called by passing the value selected in ccType.
If this type is not yet set for ccSelection, the dropdown entries are set according to the selected type.

Related

VBA Populating Combobox With Alternative Text

New to VBA so please forgive what may seem a simple question.
Using MS Word I have produced a simple form. I have a ComboBox that is populated via an array. This works fine. What I am trying to achieve is when an option is selected in this ComboBox, an alternative text entry is actually placed into the document at a Bookmark named Advice.
I am using Bookmarks as placemarkers in the Word document. At the moment the value already defined in the ComboBox is being place in the document, instead of the alternative.
Here is my code.
Dim myArray1() As String
'Use Split function to return a zero based one dimensional array
myArray1 = Split("advice for option one|advice for option two|" _
& "advice for option three", "|")
'Use List method to populate listbox
ComboBox2.List = myArray1
Exit Sub
If ComboBox2.List = "advice for option one" Then
Advice.Text = "This piece of text for option one. It's much longer than that in the DropBox, but it is what is needed."
ElseIf ComboBox2.List = "advice for option two" Then
Advice.Text = "This piece of text for option two. It's much longer than that in the DropBox, but it is what is needed."
ElseIf ComboBox2.List = "advice for option three" Then
Advice.Text = "This piece of text for option three. It's much longer than that in the DropBox, but it is what is needed."
Else
Advice.Text = ""
End If
lbl_Exit:
Exit Sub
End Sub
I'm sure I'm doing something really silly that is stopping this from working.
Thanks!
Sorry, I've just realised that I had missed the key part. Unsurprisingly this still doesn't work.
I've provided the rest of it and included your suggestion.
Private Sub CancelBut_Click()
UserForm.Hide
End Sub
Private Sub EnterBut_Click()
Dim number As Range
Set number = ActiveDocument.Bookmarks("number").Range
number.Text = Me.TextBox1.Value
Dim Name As Range
Set Name = ActiveDocument.Bookmarks("Name").Range
Name.Text = Me.TextBox2.Value
Dim Name1 As Range
Set Name1 = ActiveDocument.Bookmarks("Name1").Range
Name1.Text = Me.TextBox2.Value
Dim Address As Range
Set Address = ActiveDocument.Bookmarks("Address").Range
Address.Text = Me.TextBox3.Value
Dim ReportDate As Range
Set ReportDate = ActiveDocument.Bookmarks("ReportDate").Range
ReportDate.Text = Me.TextBox4.Value
Dim Location As Range
Set Location = ActiveDocument.Bookmarks("Location").Range
Location.Text = Me.TextBox5.Value
Dim Reason As Range
Set Reason = ActiveDocument.Bookmarks("Reason").Range
Reason.Text = Me.ComboBox1.Value
Dim Advice As Range
Set Advice = ActiveDocument.Bookmarks("Advice").Range
Advice.Text = Me.ComboBox2.Value
Dim Office As Range
Set Office = ActiveDocument.Bookmarks("Office").Range
Office.Text = Me.TextBox6.Value
Me.Repaint
UserForm.Hide
End Sub
Private Sub ToggleButton1_Click()
If ToggleButton1.Value = True Then
ComboBox2.Visible = True
Else
ComboBox2.Visible = False
End If
End Sub
Private Sub UserForm_Initialize()
Dim myArray() As String
'Use Split function to return a zero based one dimensional array
myArray = Split("problem1|problem2|problem3|problem4|" _
& "problem5|problem6|problem7|problem8|problem9|" _
& "problem10|problem11|problem12|problem13|problem14", "|")
'Use List method to populate listbox
ComboBox1.List = myArray
Dim myArray1() As String
'Use Split function to return a zero based one dimensional array
myArray1 = Split("advice for option one|advice for option two|" _
& "advice for option three", "|")
'Use List method to populate listbox
ComboBox2.List = myArray1
End Sub
Private Sub ComboBox2_Change()
Dim Advice As Range
If ActiveDocument.Bookmarks.Exists("Advice") = True Then
Set Advice = ActiveDocument.Bookmarks("Advice").Range
Select Case ComboBox2.Value
Case "advice for option one":
Advice.Text = "This piece of text for option one."
Case "advice for option two":
Advice.Text = "This piece of text for option two."
Case "advice for option three":
Advice.Text = "This piece of text for option three."
End Select
ActiveDocument.Bookmarks.Add "Advice", Advice
End If
End Sub
You haven't shown the context in which the code is run. What's the sub, and how is it getting called? And you haven't what type of object the Advice variable is or how it got set. Your code seems to be setting the combo items and trying to act on a combo selection in the same sub. That won't work.
You should create an event procedure within the form to populate the combo when the dialog is initialized.
Private Sub UserForm_Initialize()
Dim myArray1() As String
'Use Split function to return a zero based one dimensional array
myArray1 = Split("advice for option one|advice for option two|" _
& "advice for option three", "|")
'Use List method to populate listbox
ComboBox1.List = myArray1
End Sub
The have another event procedure within the form for a combo change event:
Private Sub ComboBox1_Change()
Dim Advice As Range
If ActiveDocument.Bookmarks.Exists("advice") = True Then
Set Advice = ActiveDocument.Bookmarks("advice").Range
Select Case ComboBox1.Value
Case "advice for option one":
Advice.Text = "This piece of text for option one."
Case "advice for option two":
Advice.Text = "This piece of text for option one."
Case "advice for option three":
Advice.Text = "This piece of text for option one."
End Select
End If
End Sub
This will replace the bookmark placeholder text with the indicated text. Note: the replacement will get rid of the bookmark as well, so it will only work once unless you reset the bookmark. If you want the bookmark to remain, you need to recreate it. The range object hasn't changed, so you can use that to create the new bookmark:
Private Sub ComboBox1_Change()
Dim Advice As Range
If ActiveDocument.Bookmarks.Exists("advice") = True Then
Set Advice = ActiveDocument.Bookmarks("advice").Range
Select Case ComboBox1.Value
Case "advice for option one":
Advice.Text = "This piece of text for option one."
Case "advice for option two":
Advice.Text = "This piece of text for option two."
Case "advice for option three":
Advice.Text = "This piece of text for option three."
End Select
ActiveDocument.Bookmarks.Add "advice", Advice
End If
End Sub
So now, after you select an option in the combo box, the text in the doc will be updated, and the bookmark will be reset to the new text. So, you can make a different choice, and the text will be updated again.
Private Sub ComboBox2_Change()
Dim Advice As Range
If ActiveDocument.Bookmarks.Exists("Advice") = True Then
Select Case ComboBox2.Value
Case "advice for option one":
***Advice.Text = "This piece of text for option one."***
Case "advice for option two":
Advice.Text = "This piece of text for option two."
Case "advice for option three":
Advice.Text = "This piece of text for option three."
End Select
End If
End Sub
You are over writing the text at the bookmark with the following code which is probably run when the form is closed.
Private Sub EnterBut_Click()
...
Set Advice = ActiveDocument.Bookmarks("Advice").Range
Advice.Text = Me.ComboBox2.Value
...
End Sub

Dependent ComboBoxes

I would like to have a word document that has 2 comboboxes. Combobox1 will have a selection and the second will be populated dependent on Combobox1's selection.
The following code executes the legacy controls style, but I want active x combo boxes. I also have a constraint that comments need to be able to be entered in the word doc, and restricting form fields disables that (why the legacy style won't work).
Sub Dropdowns()
Dim xDirection As FormField
Dim xState As FormField
On Error Resume Next
Set xDirection = ActiveDocument.FormFields("QSystem")
Set xState = ActiveDocument.FormFields("FType")
If ((xDirection Is Nothing) Or (xState Is Nothing)) Then Exit Sub
With xState.DropDown.ListEntries
.Clear
Select Case xDirection.Result
Case "Type1"
.Add "SubType1"
.Add "SubType2"
Case "Production and In-Process Controls"
.Add "SubType3"
.Add "SubType4"
End Select
End With
End Sub

use a button on userform to get a variable and continue with sub

I have a userform in excel where a combobox compiles a dropdown using a range from another sheet. I've defined the dropdown using a dictionary from the range and forced the combobox to match (this is done to ensure the user tries to find the company prior to adding a new one). I do however, want them to be able to add new companies to the list if absolutely needed, thus have a button labeled "add company," and now need it to add the company they input into the list/dictionary, any ideas?
I would like to avoid having to launch a whole new userform, optimally I thought of an input box on_click of the button, but I am not sure how to force that variable back into the original userform.
My current code is:
Private Sub UserForm_Initialize()
Dim Acctsht As Worksheet
Dim ValSet
Dim FinanInst
Dim objFinanInst As Object
Dim objAcctType As Object
Dim objNickname As Object
Dim objFourDig As Object
Dim objAcctClass As Object
Dim objDescript As Object
Dim CompanyDict As New Scripting.Dictionary
Dim Tempsht As Worksheet
Dim NewCompTemp As String
Set Acctsht = ActiveWorkbook.Sheets("Accounts")
With Acctsht.Range("b2:b" & Range("b:b").SpecialCells(xlLastCell).Row)
ValSet = .Value
End With
With CompanyDict
.comparemode = 1
For Each FinanInst In ValSet
If Not .exists(FinanInst) Then .Add FinanInst, Nothing
Next
If .Count Then CBoxFinanInst.List = Application.Transpose(.keys)
End With
With CboxAcctType
.AddItem "Checking Account"
.AddItem "Fixed Loan"
.AddItem "Investment Account"
.AddItem "Money Market Account"
.AddItem "Revolving Credit"
.AddItem "Savings Account"
End With
With CBoxAcctClass
.AddItem "Asset"
.AddItem "Liability"
End With
End Sub
Private Sub CButtonAddCompany_Click()
Dim NewCompTemp As String
Unload FrmCreateAccount
NewCompTemp = InputBox("Please enter new company exactly as you wish it to appear", Title:="Create New Company")
FrmCreateAccount.Show (NewCompTemp)
Exit Sub
End Sub
In response to Jean-Pierre's comment below, I've tried the following code, but it's still not working:
Private Sub CButtonAddCompany_Click()
Dim NewCompTemp As String
Dim Acctsht As Worksheet
Dim CompanyDict As New Scripting.Dictionary
Set Acctsht = ActiveWorkbook.Sheets("Accounts")
NewCompTemp = InputBox("Please enter new company exactly as you wish it to appear", Title:="Create New Company")
With Acctsht.Range("b2:b" & Range("b:b").SpecialCells(xlLastCell).Row)
ValSet = .Value
End With
With CompanyDict
.comparemode = 1
For Each FinanInst In ValSet
If Not .exists(FinanInst) Then .Add FinanInst, Nothing
Next
If .Count Then CBoxFinanInst.List = Application.Transpose(.keys)
End With
With CompanyDict
.Add CompanyDict.Count + 1, NewCompTemp
End With
Exit Sub
End Sub
Only the original dropdown list in the combobox appears, regardless of what is entered and stored as NewCompTemp.
I got it, thanks to Jean-Pierre for sending me in the right direction! I didn't realize I could run the subroutine and have it reset the dictionary right on the form.
Essentially, the dictionary was set from the initialize action, however, I didn't realize I could retrigger a set-up of the same dictionary on a button_click action. Once I did that and ended that sub it returned to the original userform sub and voila. Thank you for all that helped and thank you for your patience. (older biologist here learning new skills).

VBA: TextBox and ListBox

On my UserForm I have a TextBox where is write down my Serial Numbers, something like 421012.
Below it I have a ListBox with options like "Tools, Bench, Wheel"
What I'm attemting to do:
After I type my Serial that I just typed in, I click on one of the options in the ListBox and it should put a value behind my Serial.
Something like this: 421012 + "selecting Tools" =42101215
the "Bench" would get an result of 42101245
My code so far:
Private Sub UserForm_Initialize()
With ListBox1
.AddItem "Tools"
.AddItem "Bench"
.AddItem "Wheel"
End With
End Sub
Somehow I have to tell VBA that Tools equals 15 or Bench equals 45 etc.etc.
Add a second column and then reference that when you're doing your concatenation of the value. "42012" & me.listbox.column(1) should return the value of whatever is selected
with listbox
.columncount = 2
.additem
.list(1,0) = "Tools"
.list(1,1) = 15
.list(2,0) = "Bench"
.list(2,1) = 45
.list(3,0) = "Wheel"
.list(3,1) = 75
end with
I use this much more frequently with objects than with intrinsic types, but another option is to store a Dictionary containing lookups keyed on your ListBox items:
'Module level variable
Private SerialLookup As Scripting.Dictionary
Private Sub UserForm_Initialize()
Set SerialLookup = New Scripting.Dictionary
With SerialLookup
.Add "Tools", "15"
.Add "Bench", "45"
.Add "Wheel", "42"
End With
ListBox1.List = SerialLookup.Keys()
End Sub
Then you can retrieve whatever value you need by using it as an index into the Dictionary, i.e.:
TextBox1.Value = "421012" & SerialLookup.Item(ListBox1.Value)

Populate Combobox2 Based on Previous Combobox1 Selection

I have two combobox.The first combobox has three items as:{One, Tow, Three} now I would like to load the second combobox based on what user select in combobox1.
For example if user select One in the from combobox1 then namebox1 will populate to combox2
and if if user select Two in the from combobox2 then namebox2 will populate to combox2 and so on..
Can you please let me know how I can do this in VBA?
Thanks
Here is the Update Code:
Private Sub ComboBox1_Change()
Me.ComboBox2.Clear
Select Case Me.ComboBox1.Value
Case "One"
With Me.ComboBox2
.RowSource = "nameBox1"
End With
Case "Two"
With Me.ComboBox2
.RowSource = "nameBox1"
End With
Case "Three"
With Me.ComboBox2
.RowSource = "nameBox1"
End With
End Select
End Sub
Please be advise that I didn't use .addItem to populate the ComboBox1. It hasbeen populate by same method .RowSource which is usinf excel collection selection box
The easiest way to do this would be using a Select Case statement.
Suppose you had
Private Sub ComboBox1_Change()
Me.ComboBox2.Clear
Select Case Me.ComboBox1.Value
Case "One"
' If your data was information you wanted to put in yourself:
With Me.ComboBox2
.AddItem "Adam"
.AddItem "Allen"
.AddItem "Andy"
End With
Case "Two"
' If your data existed in a worksheet range
ComboBox2.RowSource = MyRange.Address
End With
End Select
End Sub
I hope this explains enough to get you going - Otherwise, I'm a bit confused - Can you explain what you mean by NameBox in your question