Excel/VBA uncheck checkboxes if mandatory field is empty - vba

I wrote a function which for each checkbox in document check if field C140 is empty if is then uncheck checkbox in same row.
Sub MarkCheckBoxes()
Dim chk As CheckBox
Dim ws As Worksheet
Set ws = ActiveSheet
For Each chk In ws.CheckBoxes
If ws.Range("C140").Value = "" Then
chk.Value = False
Else
chk.Value = True
End If
Next chk
End Sub
Now I want change it that for each row check if mandatory fields are empty if is then uncheck checkbox in the same row as empty field, also I need clean row color by:
EntireRow.Interior.ColorIndex = xlColorIndexNone
When I changed range("c140") to range("c140:c150") then I had an error mismatch..
ALSO
Ralph give me an answer for first part, but now I have another problem.
I'd like to make some function which allow me check if any of field in row 149 is text "Mandatory then it check if rows belows are empty if is then do uncheck. So I tried sth like this:
If ws.Rows("149") = "Mandatory" Then
If ws.Range("C" & chk.TopLeftCell.Row).Value
But I don't have any idea how to write second if to check value in each column

Use the Cells property of the Worksheet instead of the Range like this in your If statent:
If ws.Cells(3, chk.TopLeftCell).Value = ""

I believe you might be looking for something like this:
Sub MarkCheckBoxes()
Dim chk As CheckBox
Dim ws As Worksheet
Set ws = ActiveSheet
For Each chk In ws.CheckBoxes
If ws.Range("C" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
Else
chk.Value = True
End If
Next chk
End Sub
Explanations:
I changed merely the row for C140 to C + the row number in which the checkbox is located. I hope this is what you've been looking for.
In respect to your initial attempt to change Range("C140") (which is one cell) to a range of cells like C140:C150: of course that cannot work. That would be like please compare this apple to these 10 apples. In return you would get 10 answers some of which might be true and others might be false for your If clause. VBA wouldn't know which ones of the ture or the false to take.

Related

Add an extra filter on field 1 in VBA

I'm using a filter on a sheet in Excel. All I want to do is uncheck "empty cells" in field 1 of my filterrange. I know how to uncheck the "empty cells" but the existing filter (made by user) must stay active.
Code I'm using to get the name of the filterrange:
Dim obj As ListObject
Dim Tabel As String
Dim filter As Boolean
filter = False
For Each obj In ActiveSheet.ListObjects
Tabel = obj.Name
Exit For
Next
Code that I use to uncheck "empty cells" when no filter is applied:
ActiveSheet.ListObjects(Tabel).Range.AutoFilter field:=1, Criteria1:="<>"
What I prefer to get is the actual filter used in field 1, add the criteria:="<>" do my thing en reapply the filter applied by the user.
Thing I was trying:
Dim ActieveFilters As String
Dim FilterArray()
Dim LaatsteFilter As Long
Dim i As Long
With ActiveSheet.ListObjects(Tabel).AutoFilter.Filters(1)
ReDim FilterArray(1 To .Count)
For f = 1 To .Count
With .Item(f)
If .On Then
FilterArray(f) = Criteria1
End If
End With
Next f
End With
Active filters

Finding a cell based on the header of a section of data, then selecting the last row of that section

I am attempting to find the text of a header row based on the value of a cell relative to the cell that is clicked in. The way I have attempted to do this is follows:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim var1 As Variant
Dim var2 As Variant
Dim var3 As Variant
Dim FormName As String
FormName = "New Form"
Static NewFormCell As Range
Application.ScreenUpdating = False
If Not Intersect(Target, Range("G16:X80")) Is Nothing Then
If Target.Cells.Count = 1 Then
var1 = Cells(Target.Row, 2).Value
var2 = Cells(15, Target.Column).Value
If Not (IsEmpty(var1)) And Not (IsEmpty(var2)) And var2 <> "+" And Target.Interior.ColorIndex <> 2 And Target.Borders(xlEdgeLeft).LineStyle <> xlNone Then
If IsEmpty(Target) Then
Target.Value = "X"
Target.HorizontalAlignment = xlCenter
Target.VerticalAlignment = xlCenter
Target.Font.Bold = True
Dim Header As Range
Set Header = Range("A54:E160").Find(var2, LookIn:=xlValues)
Header.Offset(1, 1).End(xlDown).EntireRow.Select
Dim CopyCell As Range
'Header.End(xlDown).EntireRow.Insert
'Set CopyCell = Header.End(xlDown). [offset?]
'CopyCell.Value = var1
Else
Target.ClearContents
End If
Else
Exit Sub
End If
End If
End If
Application.ScreenUpdating = True
End Sub
The issue is VBA is throwing Run-Time Error 91 ("Object variable or With block variable not set"). It then highlights the last row in that section of code. Since I set that variable in the previous line, I'm not sure why I'm receiving this error or if I'm even going about this the right way.
Any input would be greatly appreciated!
EDIT: I cleared the above issue by searching over a wider range. The cell I wanted to select was merged, but I still assumed the value was stored within column A. But this code still isn't quite doing what I'd like it to:
I want to select the last row in the section (not the last row of data in the sheet, but the last contiguous data in column B), but right now my code is jumping me all the way to the bottom of the sheet.
The problem is that your .Find isn't finding the value. In this case, you can add some code to handle that.
...
Dim Header As Range
Set Header = Range("A59:A159").Find(var2, LookIn:=xlFormulas)
If Header Is Nothing Then
' There's no value found, so do something...
msgbox(var2 & " was not found in the range, will exit sub now."
Exit Sub
End If
MsgBox Header
...
...of course there are myriad ways/things you can do to handle this. If you still want to execute other code, then wrap everything in an If Header is Nothing Then // 'do something // Else // 'other code // End IF type thing.
It really just depends on what you want to do. Again, your error is being caused by the fact that the var2 isn't being found, so just find other things to do in that case.

Hiding a variable RangeName based on value in other sheet

At the moment I'm working on making a working code smaller using an array. I will explain the code shortly;
If a certain part is required to be in a datasheet (this worksheet is called "High Pressure Grinding Rolls"), then the user can define this by putting in value "a" on Sheets("Invulformulier"). Now there are several parts which can be on the datasheet if the cell value is "a". If we have "partA", "partB" and "partC", the RangeName of the cell will be the name of the part on Sheets("Invulformulier"). The RangeName of the range on Sheets("High Pressure Grinding Rolls") will be the name of the part + "1". For example "partA1". This range must be hidden depending on if the user puts in "a" for "partA".
This is the code I used and worked, but is specific to the cell names:
Sub Hidecellv1 ()
If Range("partA").Value = "a" Then
Sheets("High Pressure Grinding Rolls").Range("partA1").EntireRow.Hidden = False
ElseIf Range("partA").Value = "" Then
Sheets("High Pressure Grinding Rolls").Range("partA1").EntireRow.Hidden = True
End If
End Sub
This code is very specific and I want to make an array. This is what I have so far:
Sub Hidecellwitharray ()
Dim rngName As Range
Dim cell As Range
Application.ScreenUpdating = False
For Each cell In Range("Checkbox") 'Where user puts in value "a" or not
If cell.Value = "a" Then
Sheets("High Pressure Grinding Rolls").Range(RangeName & "1").EntireRow.Hidden = False
Else
Sheets("High Pressure Grinding Rolls").Range(RangeName & "1").EntireRow.Hidden = True
End If
Next cell
Application.ScreenUpdating = True
End Sub
The searching for value "a" for every part works, but I can't get it to work to hide the parts in the datasheet if value "a" is or isn't inserted. How do I refer to a variable RangeName?
If I correctly understood your issue you could try this:
Option Explicit
Sub Hidecellwitharray()
Dim cell As Range
Application.ScreenUpdating = False
For Each cell In Range("Checkbox") 'Where user puts in value "a" or not
Sheets("High Pressure Grinding Rolls").Range(Split(cell.Name.Name, "!")(1) & "1").EntireRow.Hidden = Not cell.Value = "a"
Next cell
Application.ScreenUpdating = True
End Sub
Does this do as you require? It will hide all named ranges on the 'High Pressure Grinding Rolls' sheet, then show the row containing the corresponding checkbox value.
I found helpful information on the following page: Loop through all named ranges in a Excel Sheet
Sub Hidecellv1()
Dim nm
Dim rngName
For Each nm In ThisWorkbook.Names
If Left(nm.Name, 4) = "Part" Then
Sheets("High Pressure Grinding Rolls").Range(nm).EntireRow.Hidden = True
End If
Next nm
rngName = Range("checkbox").Value
Sheets("High Pressure Grinding Rolls").Range("Part" & rngName & "1").EntireRow.Hidden = False
End Sub

In a specific row of a table replace a "*" with a checked checkbox, and "" with a checkbox that is not checked

I have a couple of tables and want to replace column 2 or column 5 (if it exists) with check boxes.
If there is an asterisk in the cell, I want the check box checked = True.
If there's no asterisk, the cell will only be a unchecked check box. These check boxes are from the developer tab, under controls, legacy forms.
I researched but failed:
replacing an asterisk with a check box (checked)
limiting it to a specific column (see image)
replacing a blank cell with a check box (unchecked)
limiting the action to a specific column (2 and 5 (if it exists))
Dim oCell As Cell
Dim oRow As Row
For Each oRow In Selection.Tables(1).Rows
For Each oCell In oRow.Cells 'this won't work specifically with my example, needs to be a little more specific
If oCell.Range.Text = "*" Then
MsgBox oCell.RowIndex & ", " & oCell.ColumnIndex & " check it!"
'I don't how to put in a check box here
End If
Next oCell
Next oRow
'I want to combine the top code and code below...right?
'do for each cell in column 2
With ActiveDocument.FormFields.Add(Range:=ActiveDocument.Selection, Type:=wdFieldFormCheckBox)
If cellvalue = "" Then 'just verbal logic here
.CheckBox.Value = False
End If
If cellvalue = "*" Then 'just verbal logic here
.checkbox.Value = True
End If
End With
Here's how I would do this:
Dim objDoc As Document
Dim oCell As Cell
Dim oCol As Column
Dim objTable As Table
Dim bFlag As Boolean
Set objDoc = ActiveDocument
Set objTable = Selection.Tables(1)
'This may or may not be necessary, but I think it's a good idea.
'Tables with spans can not be accessed via the spanned object.
'Helper function below.
If IsColumnAccessible(objTable, 2) Then
For Each oCell In objTable.Columns(2).Cells
'This is the easiest way to check for an asterisk,
'but it assumes you have decent control over your
'content. This checks for an asterisk anywhere in the
'cell. If you need to be more specific, keep in mind
'that the cell will contain a paragraph return as well,
'at a minimum.
bFlag = (InStr(oCell.Range.Text, "*") > 0)
'Delete the content of the cell; again, this assumes
'the only options are blank or asterisk.
oCell.Range.Delete
objDoc.FormFields.Add Range:=oCell.Range, Type:=wdFieldFormCheckBox
'Set the value. I found some weird results doing this
'any other way (such as setting the form field to a variable).
'This worked, though.
If bFlag Then
oCell.Range.FormFields(1).CheckBox.Value = True
End If
Next oCell
End If
'Then do the same for column 5.
Public Function IsColumnAccessible(ByRef objTable As Table, iColumn As Integer) As Boolean
Dim objCol As Column
'This is a little helper function that returns false if
'the column can't be accessed. If you know you won't have
'any spans, you can probably skip this.
On Error GoTo IsNotAccessible
IsColumnAccessible = True
Set objCol = objTable.Columns(iColumn)
Exit Function
IsNotAccessible:
IsColumnAccessible = False
End Function

Loop through PivotItems: runtime error 91

I have a dataset in a worksheet that can be different every time. I am creating a pivottable from that data, but it is possible that one of the PivotItems is not there. For example:
.PivotItems("Administratie").Visible = False
If that specific value is not in my dataset, the VBA script fails, saying that it can't define the item in the specified Field. (error 1004)
So I thought a loop might work.
I have the following:
Dim pvtField As PivotField
Dim pvtItem As PivotItem
Dim pvtItems As PivotItems
For Each pvtItem In pvtField.pvtItems
pvtItem.Visible = False
Next
But that gives me an 91 error at the For Each pvtItem line:
Object variable or With block variable not set
I thought I declared the variables well enough, but I am most likely missing something obvious...
I've got it! :D
Dim Table As PivotTable
Dim FoundCell As Object
Dim All As Range
Dim PvI As PivotItem
Set All = Worksheets("Analyse").Range("A7:AZ10000")
Set Table = Worksheets("Analyse").PivotTables("tablename")
For Each PvI In Table.PivotFields("fieldname").PivotItems
Set FoundCell = All.Find(PvI.Name)
If FoundCell <> "itemname" Then
PvI.Visible = False
End If
Next
woohoo
Thanks to MrExcel, the answer was there after all, though deeply buried.
For Each pvtField In Worksheets("my_sheet").PivotTables("my_table").PivotFields
For Each pvtItem In pvtField.PivotItems
Debug.Print vbTab & pvtItem.Name & ".Visible = " & pvtItem.Visible
/*.PivotItems(pvtItem).Visible = False*/
Next
Next
.PivotItems("certain_Item").Visible = True
That doesn't work still... all the variables are still visible. No error is shown, it compiles yet the values are still there.
The commented line I added there was my own "invention" but it's is not valid.
Edit: Quicky question: Can I use an IF statement to check if a certain PivotItem is actually in the PivotTable Data? Something like
If PivotItem("name_of_the_thing") = present Then {
do_something()
}
When I implement the code posted by Patrick, an -
Unable to set the visible property of the PivotItem class
- error is thrown.
Microsoft admits there's a bug: M$ help
But just hiding the line... is not an option ofcourse.
Try something like this:
Public Function Test()
On Error GoTo Test_EH
Dim pvtField As PivotField
Dim pvtItem As PivotItem
Dim pvtItems As PivotItems
' Change "Pivot" to the name of the worksheet that has the pivot table.
' Change "PivotTable1" to the name of the pivot table; right-click on the
' pivot table, and select Table Options... from the context menu to get the name.
For Each pvtField In Worksheets("Pivot").PivotTables("PivotTable1").PivotFields
Debug.Print "Pivot Field: " & pvtField.Name
For Each pvtItem In pvtField.VisibleItems
pvtItem.Visible = False
Next
Next
Exit Function
Test_EH:
Debug.Print pvtItem.Name & " error(" & Err.Number & "): " & Err.Description
Resume Next
End Function
If you want a function to just test for the existence of a pivot item, you can use something like this:
Public Function PivotItemPresent(sName As String) As Boolean
On Error GoTo PivotItemPresent_EH
PivotItemPresent = False
For Each pvtField In Worksheets("Pivot").PivotTables("PivotTable1").PivotFields
For Each pvtItem In pvtField.VisibleItems
If pvtItem.Name = sName Then
PivotItemPresent = True
Exit Function
End If
Next
Next
Exit Function
PivotItemPresent_EH:
Debug.Print "Error(" & Err.Number & "): " & Err.Description
Exit Function
End Function
You can call this from your code like this:
If PivotItemPresent("name_of_the_thing") Then
' Do something
End If
The error is thrown at the end of the loop.
I combined both answers from Patrick into the following:
With ActiveSheet.PivotTables("Table").PivotFields("Field")
Dim pvtField As Excel.PivotField
Dim pvtItem As Excel.PivotItem
Dim pvtItems As Excel.PivotItems
For Each pvtField In Worksheets("Sheet").PivotTables("Table").PivotFields
For Each pvtItem In pvtField.PivotItems
If pvtItem.Name = "ItemTitle" Then
pvtField.PivotItems("ItemTitle").Visible = True
Else
pvtField.PivotItems(pvtItem.Name).Visible = False
End If
Next
Next
End With
If the Item matches a particular string, that Item is set True. Else; Item set False. At the False condition the error is thrown.
I know there is exactly one match for the True condition. Though when I 'F8' my way through the macro, the True condition is never entered...
And that explains the error, everything is set False. (thanks Patrick!)
Leads me to the question... what exactly IS a PivotItem?
Idea of the thing:
It solves (or should solve) the following: a set of Data with a variable size where, for this specific table, one column is of interest. From that column I need the count of a value and have that put in a table. There are some conditions to the table, and a combination with another column is needed as well, so PivotTable is the best solution.
The problem is: in some datasets that one specific value does not appear. The values that DO appear are different every time.
The PivotItems are the individual values in a field (column, row, data). I think of them as the "buckets" that hold all the individual data items you want to aggregate.
Rather than go through all the pivot table fields (column, row, and data), you can just go through the fields you're interested in. For example, this code will show only the specified pivot items for the specified field:
Public Sub ShowInPivot(Field As String, Item As String)
On Error GoTo ShowInPivot_EH
Dim pvtField As PivotField
Dim pvtItem As PivotItem
Dim pvtItems As PivotItems
For Each pvtItem In Worksheets("Pivot").PivotTables("PivotTable1").PivotFields(Field).PivotItems
If pvtItem.Name = Item Then
pvtItem.Visible = True
Else
pvtItem.Visible = False
End If
Next
Exit Sub
ShowInPivot_EH:
Debug.Print "Error(" & Err.Number & "): " & Err.Description
Exit Sub
End Sub
Suppose I have a pivot table showing the count of issues per customer release and where they were detected in our SDLC. "Customer" and "Release" are column fields and "Phase" is a row field. If I wanted to limit the pivot table to counting issues for CustomerA, Release 1.2 during QA I could use the sub above like this:
ShowInPivot "Customer", "CustomerA"
ShowInPivot "Release", "1.2"
ShowInPivot "Phase", "QA"
You can't say ".PivotItems(pvtItem).Visible" outside a "With" block. Say "pvtField.PivotItems(pvtItem.Name).Visible = False" instead.
I also edited my original answer to include error handling for when Excel can't set the Visible property. This happens because the Pivot table needs at least one row field, one column field and one data item, so the last of each of these can't be made invisible.
You 'll also get the 1004 errror when trying to access a pivot item that is already invisible; I think you can ignore those.
I had same error message too when trying to set pivotitem visible true and false .. this had worked previously, but wasn't working any more ... i was comparing two values, and had not explicitly changed string to integer for comparison .. doing this made error disappear..
.. so if you get this message, check if any values being compared to make the item visible or not are being compared properly .. otherwise pivotitem is null and it can't make that visible or not.
I had an error that said "unable to set the visible property of the pivot item class"
at this line:
For Each pi In pt.PivotFields("Fecha").PivotItems
If pi.Name = ffan Then
pi.Visible = True
Else
pi.Visible = False '<------------------------
End If
Next pi
Then i read on internet that I had to sort manual and then clear the cache. i did that but the error still appeared..... then i read that it was because i had date on that pivot field so i change it firs my colum to general number then the date i wanted to set visible i change it to general number too. then no problem!!!!!!!!!!!!!!.... here it is.... i hope this can be helpfull because i was desperate!!!
Dim an As Variant
an = UserForm8.Label1.Caption 'this label contains the date i want to see its the pivot item i want to see of my pivot fiel that is "Date"
Dim fan
fan = Format(an, "d m yyyy")
Dim ffan
ffan = Format(fan, "general number")
Sheets("Datos refrigerante").Activate 'this is the sheet that has the data of the pivottable
Dim rango1 As Range
Range("B1").Select
Range(Selection, Selection.End(xlDown)).Select
Set rango1 = Selection
ActiveSheet.Cells(1, 1).Select
rango1.Select
Selection.NumberFormat = "General" 'I change the format of the column that has all my dates
'clear the cache
Dim pt As PivotTable
Dim ws As Worksheet
Dim pc As PivotCache
'change the settings
For Each ws In ActiveWorkbook.Worksheets
For Each pt In ws.PivotTables
pt.PivotCache.MissingItemsLimit = xlMissingItemsNone
Next pt
Next ws
'refresh all the pivot caches
For Each pc In ActiveWorkbook.PivotCaches
On Error Resume Next
pc.Refresh
Next pc
'now select the pivot item i want
Dim pi As PivotItem
Set pt = Sheets("TD Refrigerante").PivotTables("PivotTable2")
'Sets Pivot Table to Manual Sort so you can manipulate PivotItems in PivotField
pt.PivotFields("Fecha").AutoSort xlManual, "Fecha"
'Speeds up code dramatically
pt.ManualUpdate = True
For Each pi In pt.PivotFields("Fecha").PivotItems
If pi.Name = ffan Then
pi.Visible = True
Else
pi.Visible = False
End If
Next pi
pt.ManualUpdate = False
pt.PivotFields("Fecha").AutoSort xlAscending, "Fecha"
Use Caption instead of Name.
For Each pvtItem In ActiveSheet.PivotTables("PivotTable1").PivotFields("Something").PivotItems
If Not pvtItem.Caption = "Example" Then
pvtItem.Visible = False
End If
Next