Compare selected values of two Excel 2013 Powerpivot Slicers in VBA - vba

I have 2 pivot tables with powerpivot connection, and I need to propagate selected values from one slicer (connected to table1) to another slicer (connected to table2):
Dim sl As Variant
sl = ActiveWorkbook.SlicerCaches("Slicer_V").VisibleSlicerItemsList
ActiveWorkbook.SlicerCaches("Slicer_V1").VisibleSlicerItemsList = sl
Works perfectly but calls recalculation of table2 every time.
I just want to avoid redundant calculations by adding this check before my code:
if(Slicer_2.SelectedValues = Slicer_1.SelectedValues) then: exit sub
plz advice how to comapare them

Here's code I use to work with slicers:
Sub SetSlicer(ByVal SlicerName As String, ByVal value As String)
If value = "clear" Then
'Clearing takes a while to refresh, so only do if slicer is filtered
If Right(ThisWorkbook.SlicerCaches(SlicerName).VisibleSlicerItemsList(1), 5) <> "[All]" Then
ThisWorkbook.SlicerCaches(SlicerName).ClearManualFilter
End If
Else
'Setting a value takes a while on pivots, so only do if slicer is a different value.
'Note that if more than one value set in slicer, this code could fail to reset a slicer that needs reset. I'll take the chance...
If ThisWorkbook.SlicerCaches(SlicerName).VisibleSlicerItemsList(1) <> value Then
On Error Resume Next
ThisWorkbook.SlicerCaches(SlicerName).VisibleSlicerItemsList = Array(value)
If Err.Number = 5 Then
MsgBox "Error. Confirm that " & SlicerName & " exists.", vbCritical + vbOKOnly
End If
On Error GoTo 0
End If
End If
End Sub
Function GetSlicer(SlicerName As String, Optional item As Integer = 1) As Variant
On Error Resume Next
GetSlicer = ThisWorkbook.SlicerCaches(SlicerName).VisibleSlicerItemsList(item)
On Error GoTo 0
End Function

Related

VBA_Processing a value as 29160012040000TZ

I created a couple of user forms which operate a data in separate report workbook. My script can successfully proceed a value in digit type. Unfortunately the circumstances have changed and now it has to work with a Serial Numbers as: 29160012040000TZ. With that new value script after starting the Sub, open a report, but it never enter into a 'with' statement. It doesn't look for a value or doing something else. Just open a report workbook and freeze.
Below you can see the code lines where issue is present and a little description:
Single_PHA is a text window in User Form where user can enter a a value, proceeding value is 29160012040000TZ
Private Sub Wydaj_button_Click()
Workbooks.Open Filename:="N:\ENGINEERING\1. ENGINEERS\Mateusz Skorupka\PHA_Cleaning_report_path\PHA_CLEANING_REPORT.xlsm", ReadOnly:=False
Dim REPORT As Workbook
Set REPORT = Application.Workbooks("PHA_CLEANING_REPORT.xlsm")
Set TABLE = REPORT.Worksheets("Main_table")
...
With TABLE.Range("A1")
If Single_PHA = True Then
If Not IsError(Application.Match(Single_PHA.Value, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA.Value, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
In VBA I don't know how to open something like debugger or make the print instruction which would show me how the variables look on specific steps.
I am not sure if VBA read the value as 29160012040000TZ as string. I tried to declare at the beginning a variable as Single_PHA_STR as String and the proceed it as just text, but no wins there:
Dim Single_PHA_STR As String
...
With TABLE.Range("A1")
If Single_PHA = True Then
Single_PHA_STR = Str(Single_PHA.Value)
If Not IsError(Application.Match(Single_PHA_STR, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA_STR, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
I noticed that if in VBA IDE I write a bold value 29160012040000TZ, I get an error
Expected line number or label or statement or end of statement
and the value is highlighted in red.
Could someone help me in that field and explain the nature of issues:
To reproduce a situation you can create a simply user form with one TextBox and one CommandButton. In the same worksheet as user form in a column A put a values: 29160012040000 and 29160012042027IR
Then make a sub which execute after double click on command button with code:
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A1")
If Text_box1 = True Then
If Not IsError(Application.Match(Text_box1.Value, .Range("A:A"), 0)) Then
Text_box1_row = Worksheets("Sheet1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlValues).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
End If
End With
End Sub
Then try to input in a UserForm's TextBox a value = 29160012040000 and you will see that script successfully filled a forth column in row with current date. Then try to input a value 29160012042027IR and you will see that nothing happened. Script don't proceed that value at all.
So that is my issue and question indeed. How to process a value with letters at the end like: 29160012042027IR : )
I also tried to focus a script statement on one specific cell in which is a text value "29160012042027IR" that which I input into a UserForm TextBox. Looking with a debugger both of variables in if statement have the same text value, but still script miss that statement and go to else instructions : (
I mean abut: If Range("A3").Text = Text_box1.Text Then
When I change a statement for "If Range("A3").Value = Text_box1.Value Then" the same thing happen.
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A:A")
If Text_box1 = True Then
If Range("A3").Text = Text_box1.Text Then
Text_box1_row = Worksheets("Arkusz1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlWhole).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
Else
MsgBox "Other loop"
End If
End With
End Sub
IMPORTANT NOTICE:
I found the main issue. I made wrong if condition, it should be:
If Single_PHA <> "" Then previously I have got: If Single_PHA = True Then, and there the results is a value not the boolean type.
Everything works. Thank everyone very much for help.
Topic is ready to be closed.
PS: thank you Tom for suggestion and tip with debugger: )

Run time error 424 Object Required working with UserForm

I'm trying to link a user form I built in VBA editor for MS Excel 2010 to the data in an excel worksheet, but I'm getting a
run-time error 424: Object required.
I referred to the active worksheet explicitly in my code to try and remedy this, but it still comes up with the same error. My code is:
Private Sub GetData()
Dim r As Long
r = ActiveSheet.Range("B2").Value
If IsNumeric(RowNumber.Text) Then
r = CLng(RowNumber.Text)
Else
ClearData
MsgBox "Invalid row number"
Exit Sub
End If
If r > 1 And r <= LastRow Then
cboFilterResultId.Text = FormatNumber(Cells(r, 1), 0)
txtFolderPaths.Text = Cells(r, 2)
txtFileName.Text = Cells(r, 3)
txtDeletedDate.Text = Cells(r, 4)
txtReason.Text = Cells(r, 5)
txtcboAdd.Text = Cells(r, 6)
txtcboView.Text = Cells(r, 7)
txtcboChange.Text = Cells(r, 8)
DisableSave
ElseIf r = 1 Then
ClearData
Else
ClearData
MsgBox "Invalid row number"
End If
End Sub
Where RowNumber is a textbox where the user can enter the row number for the data they want.
Please help!
I rarely use ActiveSheet just in case that isn't the sheet I'm after. Generally better to be explicit which sheet you're referring to:
r=ThisWorkbook.WorkSheets("Sheet1").Range("B2")
Right, pulling data from a worksheet to a userform... as you haven't said which line your error occurs on and you haven't given us the code for ClearData or DisableSave I'll start from scratch.
Example Form Design
I create a blank userform and add three text boxes and a spin button to it:
txtRowNumber holds the row number that the data is pulled from.
TextBox1 and TextBox2 will hold my sample values.
In the Tag property of TextBox1 I enter 1 and in the Tag property of TextBox2 I enter 2. These are the column numbers that the data will be pulled from.
In reality I usually add extra stuff, for example, 8;CPER;REQD. I'd then use some code to pull it apart so it pastes in column 8, must have a percentage and is a required entry.
spnButton is used to quickly move up or down a row.
We'll need two procedures to populate the form from the given row number and to clear all controls on the form (ready for the next row to be brought in).
Any textbox or combobox that has something in it's Tag property is cleared:
Private Sub ClearForm()
Dim frmCtrl As Control
For Each frmCtrl In Me.Controls
If frmCtrl.Tag <> "" Then
Select Case TypeName(frmCtrl)
Case "TextBox", "ComboBox"
frmCtrl.Value = Null
Case Else
'Do nothing.
End Select
End If
Next frmCtrl
End Sub
Any control that has a Tag value (it's assumed the value is correct) is populated from the specified RowNumber and column (from the Tag value). The value is always taken from the sheet called MyDataSheet in the workbook containing the VBA code (ThisWorkbook) no matter which is currently active:
Private Sub PopulateForm(RowNumber As Long)
Dim frmCtrl As Control
For Each frmCtrl In Me.Controls
With frmCtrl
If .Tag <> "" Then
.Value = ThisWorkbook.Worksheets("MyDataSheet").Cells(RowNumber, CLng(.Tag))
End If
End With
Next frmCtrl
End Sub
Whenever txtRowNumber changes the form should update with values from the indicated row. To do this we'll need to clear the form of current data and then repopulate it:
Private Sub txtRowNumber_Change()
ClearForm
PopulateForm CLng(Me.txtRowNumber)
End Sub
The spin button should increase/decrease the value in .txtRowNumber. I've added checks that it doesn't go below 1. You should also add checks that it doesn't go higher than the last populated row.
Private Sub spnButton_SpinDown()
With Me
.txtRowNumber = CLng(.txtRowNumber) + 1
End With
End Sub
Private Sub spnButton_SpinUp()
With Me
If CLng(.txtRowNumber) > 1 Then
.txtRowNumber = CLng(.txtRowNumber) - 1
End If
End With
End Sub
Finally, the form should be populated when it is first opened:
Private Sub UserForm_Initialize()
With Me
.txtRowNumber = 2
.spnButton = .txtRowNumber
PopulateForm .txtRowNumber
End With
End Sub

Excel VBA UserForm 'OK'

Does anyone know how to make a userform function in the same way as the Message Box 'ok' button? I'll explain.
I'm detecting errors in a column in a spreadsheet. When an error is found, a message box pops up as follows:
MsgBox "Please enter valid data"
When I select "OK" it goes to the next error in the column. This is great, except of course a message box is modal, which freezes the application. I want the user to be able to edit the data and then move to the next error. So, I designed a userform, which can be non-modal. Great, except I want the macro to advance to the next error. It will do that IF the user corrects the error. If they do not, it just stays at that error cell.
I know WHY this happens. My userform 'Next' button just calls the macro which finds the first error. But what I want to know is if there is a way around this.
Error checking starts at row 19 because that is where user input data starts.
I'm including a link to the spreadsheet here. Module 1 'NextValidationError' works great and proceeds to the next error. Module 14 just hangs at the error until it is resolved. I'd like it to be able to skip.
https://www.dropbox.com/s/yqko5kj19pnauc9/Transparency%20Data%20Input%20Sheet%20for%20Indirect%20Spend%20V7%2009212016%20v2%200.xlsm?dl=0
Can anyone give me advice on how to make module 14 proceed as module 1?
Something like this:
Dim r_start As Long
Sub CheckNames()
Dim r As Long
'Dim emptyRow As Boolean
If r_start = 0 Then r_start = 19
With ActiveSheet
For r = r_start To 5000
'Checks entire row for data. User may skip rows when entering data.
If WorksheetFunction.CountA(.Range(.Cells(r, 1), .Cells(r, 33))) > 0 Then
If ((.Cells(r, 2) = "") <> (.Cells(r, 3) = "")) Or _
((.Cells(r, 2) = "") = (.Cells(r, 4) = "")) Then
MsgBox "Please fill in First and Last Name or HCO in Row " & r & "."
End If
End If
Next
End With
End Sub
Unless I'm mis-reading your code you can combine your two checks with Or.
You will need some method to reset r_start when the user is done checking (if the form stays open after that).
EDIT: here's a very basic example.
UserForm1 has two buttons - "Next" and "Close"
Code for "next" is just:
Private Sub CommandButton1_Click()
ShowErrors
End Sub
In a regular module:
Dim r_start As Long
'this kicks off the checking process
Sub StartChecking()
r_start = 0
UserForm1.Show vbModeless
ShowErrors
End Sub
'a simple example validation...
Sub ShowErrors()
Dim c As Range, r As Long
If r_start = 0 Then r_start = 9
For r = r_start To 200
With ActiveSheet.Rows(r)
If Not IsNumeric(.Cells(1).Value) Then
UserForm1.lblMsg.Caption = "Cell " & .Cells(1).Address() & " is not numeric!"
r_start = r + 1
Exit Sub
End If
End With
Next r
r_start = 0
UserForm1.lblMsg.Caption = "No more errors"
End Sub

Find invalid data validation cells

Description:
I have created a custom dropdown data validation list where I can choose among several values. These values on the dropdown list changes as I need (are defined in a worksheet column X).
Problem:
My problem occurs when I choose one of those values, let say Y, from the dropdown list and then I update the data validation by removing the last inserted value (deleted the Y value from column X). By doing this the value Y present in the worksheet is no longer valid so I would like to know if there is a way to obtain a list (array or string) of cells with the invalid data.
What I have done/thought so far:
I have searched in several sites and read similar questions but I cannot find anything usefull. I thought about looping all the cells and check if the value is valid but since I have a huge amount of data I think that it is not the best approach.
Since Excel already mark these invalid data with a red circle maybe it could be possible to get the address of those marked cells?
Thanks in advance!
The correct way to obtain the invalid cells in a worksheet is using Cells.SpecialCells(xlCellTypeAllValidation).
By using some information present in Microsoft KB213773 (Q213773) - "How to create data validation circles for printing in Excel" a similar Sub can be used to loop all invalid cells and then change their values (or mark them to future edit).
Sub CorrectInvalidValues()
Dim data_range As Range
Dim invalid_cell As Range
Dim count As Integer: count = 0
Dim nr_invalid As Integer: nr_invalid = 0
Dim new_value As String
'If an error occurs run the error handler and end the procedure
On Error GoTo errhandler
Set data_range = Cells.SpecialCells(xlCellTypeAllValidation)
On Error GoTo 0
' Loop through each cell that has data validation and gets the number of invalid cells
For Each invalid_cell In data_range
If Not invalid_cell.Validation.Value Then
nr_invalid = nr_invalid + 1
End If
Next
' Editing each value
For Each invalid_cell In data_range
If Not invalid_cell.Validation.Value Then
count = count + 1
Application.Goto reference:=invalid_cell, Scroll:=True
new_value = Application.InputBox("Please insert a correct value.", "Invalid Data " & count & "/" & nr_invalid)
If Not (new_value = "False") Then
invalid_cell.Interior.ColorIndex = 0
invalid_cell.Value = new_value
Else
invalid_cell.Interior.Color = RGB(255, 0, 0)
invalid_cell.Value = "<PLEASE EDIT>"
End If
End If
Next
Exit Sub
errhandler:
MsgBox "There are no cells with data validation on this sheet."
End Sub

VBA inputbox input validation issue for excel

Excel requirement: User to enter a number via an input dialog. Rows containing that number in the designated (hard-coded) column of the current selection are to be deleted.
Regarding input validation, I have not come up with or found a solution that covers all these issues:
Empty input is not to be accepted. (Some variations I've tried treat it as zero.) Preferrably an error would be shown, but ok to treat like the cancel button if there's no better way.
Cancel button is to cancel dialog without further messages. (In the code below, it results in "invalid input."
A zero value entry must be permitted. (Not treated as cancel like in some of my attempts)
A zero value when there is no zero to match must show "Nothing to delete."
A row is not to be deleted if the cell is empty. ie. Do not match zero with an empty cell.
I've tried variations of code, but at least one issue remains in each. The code below is modified from my original post. It's my best solution so far. The only issue is that cancel results in "No value entered."
Thanks.
Sub DeleteRows()
On Error GoTo InvalidInput
Dim InputRng As Range
Dim DeleteRng As Range
Dim DeleteNum As Double
Dim DeleteV As Variant
Dim CountDelete As Long
Dim CountAreas As Long
Dim Str As String
Set InputRng = Application.Selection.Rows
DeleteV = Application.InputBox("Match Value", "Delete Rows")
'TODO Ultimate solution: Check for cancel so as not to result in "No value entered".
'NOTE: If DeleteV = Empty is true upon cancel
'NOTE this unwantingly matches zero: If DeleteV = False Then Exit Sub
'Check something was entered
If DeleteV = Empty Then
MsgBox ("No value entered.")
Exit Sub
End If
DeleteNum = CDbl(DeleteV)
'Accumulate what is to be deleted
For Each r In InputRng.Rows
'Only if cell is a number
If Not IsEmpty(r.Cells(3)) Then
If IsNumeric(r.Cells(3).Value) Then
If r.Cells(3).Value = DeleteNum Then
If DeleteRng Is Nothing Then
Set DeleteRng = r
Else
Set DeleteRng = Application.Union(DeleteRng, r)
End If
End If
End If
End If
Next
If DeleteRng Is Nothing Then
MsgBox ("Nothing to delete.")
Exit Sub
End If
CountDelete = 0
'The range may contain separated areas,
'so loop through each area to accumulate the total count
For Each a In DeleteRng.Areas
CountDelete = CountDelete + a.Rows.Count
Next a
If CountDelete > 1 Then
Str = " rows."
Else
Str = " row."
End If
'Confirm delete
If MsgBox("Confirm delete " & CountDelete & Str, vbYesNo) = vbYes Then
DeleteRng.EntireRow.Delete
End If
Exit Sub
InvalidInput:
MsgBox ("Invalid input.")
End Sub
Try it with Type 1
Syntax:
expression.InputBox(Prompt, Title, Default, Left, Top, HelpFile, HelpContextID, Type)
Type:
The following table lists the values that can be passed in the Type argument. Can be one or a sum of the values. For example, for an input box that can accept both text and numbers, set Type to 1 + 2.
Value Meaning
0 A formula
1 A number
2 Text (a string)
4 A logical value (True or False)
8 A cell reference, as a Range object
16 An error value, such as #N/A
64 An array of values
DeleteV = Application.InputBox("Match Value", "Delete Rows", Type:=1)
Sub Sample()
'~~> Only valid numbers are allowed including 0
'~~> Empty input will not to be accepted.
DeleteV = Application.InputBox("Match Value", "Delete Rows", Type:=1)
'~~> If user presses Cancel
If DeleteV = "False" Then Exit Sub
'~~> If user enters a number else it won't execute this
If DeleteV >= 0 Then
'
'~~> Rest of your code
'
End If
End Sub
Your Points which are taken care of
Empty input is not to be accepted.
Cancel button is to cancel dialog without further messages.
A zero value entry must be permitted. (Not treated as cancel like in some of my attempts)
A zero value when there is no zero to match must show "Nothing to delete." Can be handled inside the If-EndIf
A row is not to be deleted if the cell is empty. ie. Do not match zero with an empty cell. Can be handled inside the If-EndIf