Word VBA: Status of a checkbox in Word table cells - vba

I have a set of identical Word files containing a set of yes/no questions organized in a table with simple checkboxes (from the Developer tab / Content Controls) included in columns 3 and 5, corresponding to the Yes or No answer.
The Yes and No checkboxes are either checked or unchecked.
I want to count the number of Yes and No checks for each of the questions. The Word files are already available and their format cannot be changed.
As a first step in this task I am trying to recognize when a table cell contains a checkbox, and then read the status of the checkbox: checked or unchecked.
I came to the following code to identify the checkboxes. VBA complains with a compilation error: "Object Required", at line "set nitem.....".
Dim tbl As Table
Dim cl As Cell
Dim nitem As Integer
''All tables
For Each tbl In ActiveDocument.Tables
For Each cl In tbl.Rows(1).Cells
If Not cl.Range.ContentControls Is Nothing Then
Set nitem = c1.Range.ContentControls.Count
MsgBox ("Nr of Items" & nitem)
If c1.Range.ContentControls.Item(1).Type = wdContentControlCheckBox Then
''Select ...
cl.Column.Select
.........
End If
End If
Next
Next

The keyword "Set" is for objects. An Integer is not an object so your line needs to be just:
nitem = cl.Range.ContentControls.Count
without "Set"
EDIT: This would cause the error that you are referring to, but I also noticed another issue that needs to be fixed after your comment.
Note that the declared variable is "cl" where the second character is a lowercase "L". You have tried to use it as "c1" where the second character is the numeral "One" Make sure to use "CL" in all cases where this variable appears (in the line in question and also two lines below this)
If you use "Option Explicit" at the beginning of the "This_Workbook" module (or whatever module the code is in) before any Subroutines, this will help prevent misspelling errors like this as the compiler will raise an exception alerting you that the variable is not defined.

Related

Saving Custom Document Properties in a Loop

I'm trying to save the values of data that have been input into my form. There are a total of about 50 different fields to save across 5 different agents, so I loaded the data into arrays.
I've tried saving the fields in a loop, but it doesn't seem to work in a loop, only if each field has a separate line, which is a lot of code and messy. The Ag1Name, Ag2Name and Ag3Name are the names of my textboxes that the user enters to populate the form.
Sub LoadAndSaveData()
NumberofAgents = 3
Dim AgentName(3) as String
AgentName(1) = Ag1Name.Value
AgentName(2) = Ag2Name.Value
AgentName(3) = Ag3Name.Value
For Count = 1 To NumberOfAgents
With ActiveDocument.CustomDocumentProperties
.Add Name:="AgentName" & Count, LinkToContent:=False, Value:=AgentName(Count), Type:=msoPropertyTypeString
End With
Next Count
End Sub
The data doesn't get saved to the Custom Document Properties when the code is set up in a loop like the above. Since there are so many values to save and all the data is already in arrays, I would much prefer to use a loop rather than write out a separate line of code for all ~50 of the values. It does seem to work when each field is saved in a separate line of code.
I think this would probably get what you want. You don't really need to count the document properties first, only increment with the ones you want to update. Hopefully the only document properties you want contain the name AgentName in it.
ReDim AgentName(0) As String
Dim P As Long
For Each c In ThisDocument.CustomDocumentProperties
If InStr(1, c.Name, "AgentName", vbTextCompare) > 0 Then
ReDim Preserve AgentName(P)
AgentName(P) = c.Value
P = P + 1
End If
Next c
As a guest I cannot post a comment here, but the code you gave works OK here.
However, there is a problem with creating legacy custom document properties programmatically, because doing that does not mark the document as "changed". When you close the document, Word does not necessarily save it and you lose the Properties and their values.
However, if you actually open up the Custom Document Property dialog, Word does then mark the document as "changed" and the Properties are saved.
So it is possible that the difference between your two scenarios is not the code, but that in one scenario you have actually opened the dialog box to check the values before closing the document and in the other you have not.
If that is the case, here, I was able to change this behaviour by adding the line
ActiveDocument.Saved = False
after setting the property values.
If you do not actually need the values to be Document Properties, it might be better either to use Document Variables, which are slightly easier to use since you can add them and modify them with exactly the same code, or perhaps by storing them in A Custom XML Part, which is harder work but can be useful if you need to extract the values somewhere where Word is not available.
You can make this even easier by looping the controls on the UserForm, testing whether the control name contains "Ag" and, if it does, create the Custom Document Property with the control's value - all in one step.
For example, the following code sample loops the controls in the UserForm. It tests whether the controls Name starts with "Ag". If it does, the CustomDocumentProperty is added with that control's value.
Sub LoadAndSaveData()
Dim ctl As MSForms.control
Dim controlName As String
For Each ctl In Me.Controls
controlName = ctl.Name
If Left(controlName, 2) = "Ag" Then
With ActiveDocument.CustomDocumentProperties
.Add Name:=controlName, LinkToContent:=False, value:=ctl.value, Type:=msoPropertyTypeString
End With
End If
Next
End Sub
I feel a little stupid... I just realized that the reason that the code wasn't working was that the variable NumberofAgents was not being calculated correctly elsewhere in my code. I've got it working now. Thanks for your thoughts!

Input box Compile Error

I have been trying to get the name of a file name when someone uses this Macro. But for some reason every time I run the Macro I get the error:
Compile error:
Wrong number of arguments or invalid property assignment
I have looked at tons of videos and other responses but none of them have helped me deal with this error.
Sub inputbox()
Dim x As Variant
x = inputbox("Please enter your file name:", "File name")
MsgBox ("Your file name is" & x)
End Sub
Here is your procedure, corrected: (Copy & paste into a new module.)
Option Explicit
Sub MyInputBoxTest()
Dim x As Variant
x = inputbox("Please enter your file name:", "File name")
MsgBox ("Your file name is " & x)
End Sub
Explanation:
Variant was misspelled. Note that since Variant is the default data type, you actually don't need to specify it. Dim x is the same as Dim x as Variant.
You can't use names like InputBox OR MsgBox as the name of your procedure. They are reserved words -- already used by another procedure built-in to VBA, so it confuses the compiler since it doesn't know which one you're referring to.
Added a space after the word is. (purely cosmetic)
Functions like MsgBox and InputBox can be called different ways depending on whether you use brackets and whether you need to return a value.
InputBox "Hi"
InputBox ("Hi")
...either of these will run fine (but won't return the what the user enters.)
Dim x
x = InputBox ("Hi")
...will return the value to variable x, however:
x = InputBox "Hi"
...will throw an error.
It's highly recommended that, especially while learning, you add the line Option Explicit to the very top of every module. This will help "force" you to properly declare and refer to variables, objects, etc, by generating compile errors when you try to compile (F9) or run (F5) the code.

Find a Specific Cell entry in a Column in VBA

I'm working on creating a userform for reviewing an excel sheet. I need to search a specific column to see if the user has already reviewed the row. If they have, the cell will be filled with "Reviewed", if it hasn't been reviewed yet it will have "Not Reviewed" in it.
Each department has their own Column logging whether the Row has been reviewed or not. I.e. Dept1 may have reviewed the row, while Dept2 has not yet.
I've tried something like
With Sheets("ECR")
UnReviewedRow = .Range(DepartmentReviewColumn:DepartmentReviewColumn).Find(what:="Not Reviewed", after:=.Cells(DepartmentReviewColumn, 3)).Row
End With
But I'm getting an error, not quite sure where it's coming from though. The hardcoded "3" is because I know that all entries begin at row three, everything above is headers.
I've found a few different similar questions, but they all assume that the column being searched will be the same every time. My issue is that I don't want to code this for each department, I'd like to be a bit more elegant than that.
Something like this:
With Sheets("ECR")
UnReviewedRow = .Range(DepartmentReviewColumn & ":" & DepartmentReviewColumn).Find(What:="Not Reviewed", After:=.Cells(3, DepartmentReviewColumn)).Row
End With
Modifications made:
Range() now takes a properly built string argument;
Cells() now has a row number as its first argument, and a column expressed as a string as its second argument.
Note that this code will fail with Object variable or With block variable not set if the search string is not found. You can handle this situation by initializing UnReviewedRow to e.g. 0 (zero) and putting On Error Resume Next above the Find call, and On Error Resume <either 0 or your original error handler's label> below the Find call. Then, check if UnReviewedRow = 0 and act appropriately.
Always put Option Explicit at the top of modules and classes, and compile your code (Debug / Compile VBAProject). When posting, include the text of all errors encountered.

Mystery Excel semicolon mode for data validation, stops recognizeing standard comma for unknown reason

In Excel VBA how can I set cell validation so that it works in all locales?
This code works in my locale, semicolon separated
Dim mySheet As Worksheet
Set mySheet = ThisWorkbook.Worksheets("Sheet 1")
Dim myRange As Range
Dim validValues as String
validValues = "a;b;c"
Set myRange = mySheet.Cells(2, 2)
myRange.Validation.Add _
Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Formula1:=validValues
But I've seen that other locales needs comma separated
validValues = "a,b,c"
Essentially what I need is this, but I don't know how to determine 'id' in way that works in all locales.
' Internationalized delimiter
Dim id as String
id = ???
validValues = "a" & id & "b" & id & "c"
Edit:
There seems to be a "semicolon mode" of Excel that I do not understand and which I cannot reproduce reliably. I had a certain instance of Excel that got into this mode and all code run inside it worked with semicolon and not comma. I wrote a project in this instance and it worked, I would have thought I just made a mistake if not for all the code that I now have to rewrite...
Any hints in order to figure this out is appreciated.
Edit2:
After restarting Excel it changed it's mode to comma, I've been using it for a while but now this problem hit me again, Excel started using ';' (semicolon) instead of ',' (comma) as delimiter for my data validations.
This time I took a screenshot. Data validation is set to List.
Source is set to:
zero,one,both
This is the result, as you can see Excel does not care about my commas and displays all on the same line:
With source set like this it works:
zero;one;both
Result:
It is a mystery to me why Excel does this but I really need to find a way to make sure this never happens to my customer. Any help appreciated!
I have just dealed with a similar problem. I couldn't find a reason for why this happens, so I don't have a solution for good. Yet, I found a way around the problem that could be of use.
The only thing that you would need is to assign a valid value to the validated range before adding the validation.
After running your code, if the .Formula1 argument worked with semicolons, then there is no problem at all. If it didn't, the .Validation.Value property of the range returns False and you can use that as a trigger to rerun your code, replacing the semicolon separated list by a comma separated one. Then just rerun the validation.
For example:
myRange.value = "a" 'Assuming "a" is a valid value contained in the validvalues string
If myRange.Validation.Value = False Then
validvalues = replace(validvalues,";",",")
myRange.validation.modify Formula1:= validvalues
End if
Then you can clear the range value if you do not wish to have a default value shown.
I believe you are looking for a delimiter that would work on multiple scenarios (please let me know if this is not your query).
comma, semicolon, are sometimes good delimiter but often they pose serious syntax and some other string related errors .
Triple question mark ??? is also not a good choice in this case.
I prefer to go with | (the pipe) in these situations.
Sorry for the long answer :)
Microsoft says you need to use commas in VBA
https://support.microsoft.com/en-us/help/299490/data-validation-list-entries-all-on-one-line-in-excel

display searched data in listbox in vba

I am new to VBA coding..
help me in this situation..
I have a table like in sheet 1
Data table
& the user-form is like
User form
I need to display the searched data in this list-box...my logic which i have tried...
1) a variable which holds the text-box value
2) 1st tried with advanced filter but its not working
3) then tried with find function it also shows error..
I have tried but it does not display in list-box...it is my first working with list-box...thanks in advanced....
The details might well vary between Access and Excel, and the version of those tools ... I happened to use Access 2000 for this example.
In case you're not sure how to see what an icon is named: float the mouse cursor over it.
I opened the form in design view
I activated a toolbar that had the "Toolbox" icon
I selected "List box"
I clicked on the form and dragged a box shape. This made a caption box containing "List1:" and also a list box
I changed the caption to whatever matches the table I plan to use, which is "tblDomainName" hence "Domain Name:"
I opened up the properties for the list box and clicked in the "Row Source" area.
I typed "SELECT DomainName FROM tblDomainName ORDER BY DomainName" based on the table planned to use, so if your table were named "Stuff" then you'd type what's inside the double-quotes, here: "SELECT [Name] FROM Stuff ORDER BY [Name]" ... notice the square brackets in case "Name" is a reserved word that might cause confusion otherwise.
I changed to form "view" mode and clicked through the various values. They matched what's in my table, and they were sorted besides. Yay!
So, the above gets the list box basically working and gets you past your first hurdle ... as I understand it to be.
What's next? As to how you use that list box, and the selected value, to your benefit .... that depends on what the big picture is, so feel free to elaborate.
Does this help?
~Tanya
can you please show your codes you have tried? I'm sorry if I can't just comment on your question coz I'm still lacking in reputation. Thanks!
Please Try this code below:
Private Sub cmdSearch_Click()
Dim ws As Worksheet
Dim numRow As Integer
Dim found As Boolean
Set ws = ThisWorkbook.Worksheets("display")
For numRow = 1 To (ws.Range("A" & ws.Rows.Count).End(xlUp).Row)
If nameTxtBox.Value = ws.Range("A" & numRow).Text Then
nameList.AddItem (ws.Range("A" & numRow).Value)
prodList.AddItem (ws.Range("B" & numRow).Value)
saleList.AddItem (ws.Range("C" & numRow).Value)
found = True
Exit For
End If
Next numRow
If found = False Then
MsgBox "No Match Found!", vbCritical
nameList.Clear
prodList.Clear
saleList.Clear
End If
End Sub
userForm screen shot
Spread Sheet Screenshot:
hope this is what you want to do!
Thanks!