Add Conditons to Unhide column in a sheet with Mulitple Criteria - excel

A little Help again please.
Codes below work for hiding columns that do not match B5.
Now my problem is, I want to unhide column that matches values
from B6 and B7 at the same time.
Reference Values from Command Sheet Column B Row 5,6,7.
Let B5 is MARCH
Let B6 is JANUARYsample picture
Let B7 is FEBRUARY
Sheet Name (GRA_NewGen CI) Note that All Data's per row/column are here.
Range from Sheet Name to Match B5,B6,B7 is Column C Row 4 up to End of Column in row with Values.
Below is the 'Code
'Sub GRA_NewGen_CI()
Dim cell As Range
Application.ScreenUpdating = False
With Sheets("GRA_New Gen CI")
For Each cell In .Range("C4", .Range("XFD4").End(xlToLeft))
cell.EntireColumn.Hidden = cell.Value <> Sheets("Command").Range("B5") And Not IsEmpty(cell)
Next cell
End With
Application.ScreenUpdating = True
'End Sub

If all you want is to hide all rows marked "JANUARY", "FEBRUARY" etc. you will have more flexibility and faster action by using Excel's Filter functionality. Learn here about Filters.

That gave me quite a ride. All those hidden columns are tricky. But now it's your turn. Please follow the instructions.
On your 'Command' sheet, find a blank column and enter "Show All" in one of the cells and this function in the cell below that:
="Show "& B5
I prefer you to have all the 12 months in B5:B16, but if you have only Jan to Mar or prefer to change the content on the fly that is OK as well. Copy the formula down for as long as you have relevant data (month names or column captions) in column B. Give the range I just described a name. I gave it the name "DropdownList". Make sure the named range has a 'Scope' of "Workbook" (meaning, it is visible from all parts of the workbook).
Place a command button on the GRA_New sheet in position A4. Perhaps you already have a button elsewhere. In that case I will ask you to play along and make another one for now. Later you can move this button to any other location, including another sheet, but not in a column to be possibly hidden. This command button will be a Validation drop-down. Enter
"Allow" = List and
"Source" =DropdownList (including the = mark.
You should now have a validation dropdown showing "Show All" in first position, "Show January" in second, and more "Show ..." depending upon the size of the named range DropdownList. Make sure that there is a single space between in "Show January" and "Show all", not more and not less, and every line consisting of 2 words, the second of which is relevant.
Now add the following procedure to the code sheet of the "GR_New ..." sheet.
Private Sub Worksheet_Change(ByVal Target As Range)
'17 Mar 2017
If Target.Address = Range("A4").Address Then
SetDisplay_GRA_NewGen Split(Target.Value)(1)
End If
End Sub
In this procedure, please change the reference to "A4" to the cell where you have the validation dropdown.
The next procedure goes into a normal code module. By default its name would be "Module1", but you can give it any name you like.
Sub SetDisplay_GRA_NewGen(ByVal Cmd As String)
' 17 Mar 2017
Dim Spike As String
Dim CountHidden As Integer
Dim FirstColumn As Long, LastColumn As Long
Dim CapRow As Long, Cap As String
Dim C As Long
CapRow = 4
FirstColumn = 3 ' = column C
With Worksheets("GRA_New_Gen_CI")
LastColumn = .UsedRange.Columns.Count
If StrComp(Cmd, "all", vbTextCompare) Then
With Range("DropdownList")
For C = 2 To .Rows.Count
Cap = Split(.Cells(C).Value)(1)
Spike = Spike & "|" & Cap
Next C
End With
For C = FirstColumn To LastColumn ' count hidden columns
Cap = .Cells(CapRow, C).Value
If .Columns(C).Hidden Then
If .Columns(C).Hidden Or InStr(1, Spike, Cap, vbTextCompare) = 0 Then
' if Cap can't be selected it is counted as not hidden
CountHidden = CountHidden + 1
End If
End If
Next C
Application.ScreenUpdating = False
If CountHidden = 0 Then
' hide all except the specified column
.Range(.Columns(FirstColumn), .Columns(LastColumn)).Hidden = True
End If
For C = FirstColumn To LastColumn
With .Columns(C)
If .Hidden Then
Cap = .Cells(CapRow).Value
If StrComp(Cap, Cmd, vbTextCompare) = 0 Then .Hidden = False
End If
End With
Next C
Else
.Range(.Columns(FirstColumn), .Columns(LastColumn)).Hidden = False
End If
End With
Application.ScreenUpdating = True
End Sub
Look for the two declarations in this procedure:
CapRow = 4
FirstColumn = 3
Row 4 is the row on your data sheet in which the program will look for the months names. Column 3 (= "C") will be the first column in which the program will expect to find a month's name. Columns A:B will never be touched.
Now your system is ready. You will need to know how to operate it.
1. When you select "Show All" from the dropdown all columns starting from FirstColumn will be shown. Call this a reset.
2. When you select any of the items from the dropdown columns with that name in CapRow will be shown.
3. When you select another month it will be added to the one already shown.
4. When all columns are shown already, only the selected one will be displayed.
You can modify the range DropdownList anytime, make it longer or shorter. The important thing is that the names in the dropdown are available in the CapRow. The program compares them as text, meaning "show all" is the same as "SHOW ALL".

Related

How to run a function at the end of pasted data in Excel?

I have an excel sheet where I paste some data and I want to run a function automatically on pasting data at the end of each column to count the number of cells that have some text and then give that row which contains formula a specific color.
For example, I paste the below data:
And now I want to run a function at the end of each column which will display the count of cells containing 'Error'.
The function for the first column would be =countif(A2:A9, "Error"), the function for the second column would be =countif(B2:B9, "Error") and so on.
Appreciate any help in advance.
Format a blank table and create a sum row(Click in table -> Tabletools -> Sum row):
Write in the sum row your formula like: =countif([Second],"Error")
Now you can simply copy in your data and it will calculates the occurence in the last row. On pasting the table in, it will move the sum row automaticly downwards.
Expanding on Doomenik's answer
Part 1 Set your data up as a table and insert a total row. Adjust the following table name as appropriate.
Then insert total row by going into the design tab, which appears when you are inside the table range, and checking the Total Row box
A total row will appear at the bottom of the table with a dropdown icon
Starting with column A you want to select the COUNTIF function to apply to the total row which means selecting More Functions from the drop down and then typing in COUNTIF.
In the box that appears enter the following:
Notice that the entire data area of column A in the table is referenced by [ID]. This will be automatically entered when you select the data area of the table A column range when specifying the range argument to COUNTIF i.e. when selecting as below:
The criteria argument is NA() for error.
You then drag the formula from column A, in the total row, across to column C and autofill will do the rest.
Part 2: Apply conditional formatting to the total row by using
=ISFORMULA(INDIRECT("Table1[#Totals]"))
in Excel 2016 or
=LEFT(FORMULATEXT(INDIRECT("Table1[#Totals]")),8) = "=COUNTIF"
in earlier versions.
Entering the formula:
Now, specifying the range to apply to:
I messed around with specifying the last row with
=INDIRECT("Table1[#Totals]")
Turns out, Excel still converts this to the current last row range e.g.
=$A$11:$C$11
And this updates even if i add rows to the table.
Part 3: Adding new rows by pasting
Now, how to handle the adding of rows by pasting? Insert the following code by Zak into the worksheet containing the table.
Then paste the new rows into the first column of the totals row and it will update and shift the totals down.
Option Explicit
Private Const SingleRowOnly As Boolean = False
Private Const MaxRowCount As Long = 100
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ResizeRange As Range
Dim Table As ListObject
Dim TotalsShowing As Boolean
Dim ExpandTables As Boolean
Dim RowIndex As Long
Dim RowCount As Long
' Make sure sheet isn't protected
If Me.ProtectContents Then Exit Sub
' If already in a table, then exit
If Not Target.ListObject Is Nothing Then Exit Sub
' Make sure only one row is being changed
If Target.Rows.Count > 1 Then Exit Sub
' Make sure we're not in row 1
If Target.Row = 1 Then Exit Sub
' Make sure we're in the row right under the Totals row
If Target.Offset(-1, 0).ListObject Is Nothing Then Exit Sub
' Set table
Set Table = Target.Offset(-1, 0).ListObject
TotalsShowing = Table.ShowTotals
ExpandTables = Application.AutoCorrect.AutoExpandListRange
' If Totals not showing, exit
If Not TotalsShowing Then Exit Sub
' Make sure the selection is a contiguous range
If Target.Areas.Count > 1 Then Exit Sub
' Make sure Target range is within the table columns
If Target(1, 1).Column < Table.ListColumns(1).Range.Column Then Exit Sub
If Target(1, Target.Columns.Count).Column > Table.ListColumns(Table.ListColumns.Count).Range.Column Then Exit Sub
' Prepare to adjust table
Application.EnableEvents = False
Table.ShowTotals = False
Application.AutoCorrect.AutoExpandListRange = True
' Set the resize range
If WorksheetFunction.CountA(Table.Range(1, 1).Offset(Table.Range.Rows.Count + 1).Resize(1, Table.Range.Columns.Count)) > 0 Then
If Not SingleRowOnly Then
RowIndex = Target.Row
RowCount = RowIndex
Do Until WorksheetFunction.CountA(Me.Range(Me.Cells(RowCount, Table.Range(1, 1).Column), Me.Cells(RowCount, Table.Range(1, Table.ListColumns.Count).Column))) = 0 Or RowCount - RowIndex > MaxRowCount
RowCount = RowCount + 1
Loop
Set ResizeRange = Table.Range.Resize(Table.Range.Rows.Count + RowCount - RowIndex, Table.Range.Columns.Count)
Else
Set ResizeRange = Table.Range.Resize(Table.Range.Rows.Count + 1, Table.Range.Columns.Count)
End If
Else
Set ResizeRange = Table.Range.Resize(Table.Range.Rows.Count + 1, Table.Range.Columns.Count)
End If
' Make table adjustment
Table.Resize ResizeRange
' Put things back the way we found them
Application.AutoCorrect.AutoExpandListRange = ExpandTables
Table.ShowTotals = TotalsShowing
Application.EnableEvents = True
End Sub
Quoting from the link:
There are two constants declared at the top of this code.
SingleRowOnly. This specifies whether multiple rows should be included
in appending into the Table, or if only a single row should be.
MaxRowCount. As to not go crazy with appending rows to a Table
automatically, this is the maximum number of rows to include at any
one time. If SingleRowOnly is set to True, this constant is moot.
So you can adjust as appropriate.
With Autocomplete feature it should update column references automatically
EDIT
If you want to auto-do this, maybe you can try to paste the following formula at the end of your data:
=COUNTIF((INDIRECT(ADDRESS(ROW()-8;COLUMN()))):(INDIRECT(ADDRESS(ROW()-1;COLUMN()))); "Error")
Explanation
COUNTIF(range; pattern)
The range is specified with two INDIRECT functions. One pointing to the first row, and one pointing to the last one (those 8 and 1 respectively).
So the range looks like:
(INDIRECT(ADDRESS(ROW()-8;COLUMN()))) : (INDIRECT(ADDRESS(ROW()-1;COLUMN())))
NOTE that I assumed that you have 8 rows in total, but you can put any other number there

Button Generates the columns from user input but not the cell lines?

I implemented a button that ask the user where to add a column, and the button takes the user input(A-Z) and generates the column until the end of the table NOT SPREADSHEET. The column ends based on how many rows there are in my table, meaning if there are 10 rows, after the user clicks the button an inputs where they want the column to be(They input a letter of the column A-Z), I should not see a column box on line 11 of the spreadsheet.
Now I've managed to do this my issue is below:
My issue is the cells the button generate does not include the lines or boxes around the cells so that you are aware that its an extension of the table?
here is what I mean: Picture of spreadsheet
notice the i column there are no lines around the cells?
Here is code, I think I am missing a copy function after the line
shift:=xlRight, but I don't know how to implement it?
I don't want to use macros because since the tables rows and column change due to the user's input I will have to constantly hard-code the range into the macro which i dont want.
Trust me I tried it an its annoying.
Private Sub CommandButton2_Click()
Dim x As Variant
Dim ColumnNum
x = InputBox("Enter a column that you want to add: ", "What column?")
If x = "" Then Exit Sub
ColumnNum = x
ThisWorkbook.Sheets("Sheet1").Columns(ColumnNum).Insert shift:=xlRight
ThisWorkbook.Sheets("Sheet1").Columns(ColumnNum).ClearContents
End Sub
you could try this:
Private Sub CommandButton2_Click()
Dim colIndex As Variant
colIndex = Application.InputBox("Enter a column that you want to add: ", "What column?", , , , , , 2) '<--| force a text
If colIndex = "" Then Exit Sub
With ThisWorkbook.Sheets("Sheet1").Columns(colIndex) '<--| reference column you want to insert
.Insert shift:=xlRight '<--| insert a new column , then the referenced one shifts one column to the right of the inserted one
.Offset(, -2).Copy '<--| copy the column two columns to the left of the referenced one (i.e. one column left of the new one)
.Offset(, -1).PasteSpecial xlPasteFormats '<--| paste formats to the new column
Application.CutCopyMode = False
End With
End Sub

Select value from dropdown box but populate hidden column

I have a set of unique IDs and names:
ID NAME
aa Jeff
bb Matt
cc Trung
dd Trung
All IDs are unique. Names are not.
On a worksheet I have a series of columns:
Date Time ID Name Value
1/1 1:30 aa Jeff 123124
1/2 2:20 cc Trung 12443234
Right now, a user will populate the ID field, the vlookup will return Name.
Is there a way to set up a dropdown on the ID cell that shows a concatenation of the ID and Name, but when selected, stores only the ID?
The idea is that the concatenated value that appears in the dropdown (Ex: aa | Jeff) is more user-friendly that just "aa".
Well, hope my answer will help. If not, please tell me and I will try to improve it.
The code is inside the Worksheet
Private Sub ComboBox1_Change()
'Just use the frist part of the string, ID
Range("I1").Value = Split(Me.ComboBox1.Value, " | ")
'Optional, if you want to put the name using code.
'If not, just use the VLOOLUP
Range("J2").Value = Split(Me.ComboBox1.Value, " | ")(1)
End Sub
Private Sub Worksheet_Activate()
Dim r
Dim c
Dim i
Dim L
Dim myRngID As Range
r = Range("C2").End(xlDown).Row 'the final row of the ID column
c = Range("D2").Column ' the number of the column of the name
Set myRngID = Range(Cells(2, 3), Cells(r, 3)) 'use only the ID range
'Just to clean the ComboBox everytime to avoid duplicates
Me.ComboBox1.Value = ""
L = Me.ComboBox1.ListCount
On Error Resume Next
For i = 0 To L
With Me.ComboBox1
.RemoveItem i
End With
Next i
On Error GoTo 0
'Pupulate the ComboBox with the string {ID[space]|[space]NAME}
For Each i In myRngID
With Me.ComboBox1
.AddItem i.Value & " | " & i.Offset(0, 1).Value
End With
Next i
End Sub
In the worksheet just this
As you can see, the only formula in the sheet is in J1, the VlookUp. In J2 the name is inserted using VBA.
The ComboBox has any special property. Everything is in the code above.
The result is that the name is always taken from the ComboBox, and then no matter which one is selected, always will be the right one, as in the VlookUp.
This should work
Select the Cell on the Second Sheet (the one that will be the vlookup)
Go to the Data Tab > Data Validation > Data Validation
On Settings Select List > Click Source button at the right of the input box > Select Range from the first workbook Screenshot
Now copy and paste that cell in the column on the second workbook

Excel VBA defining standard user input field

I have 7 columns representing 7 diferent (let's call it) sources of input.
Row 1 of each column has the names of each source.
Row 2 of each column is a sum of all rows from the 4th down. Ex: A2 = SUM(A4:A1048576)
Since I am suposed to make random entries to each column, I want Row 3 of each column to be standard user input field so that any value input on 3rd row of each column is appended to the first empty cell in that column, triggered by some event (keypress, buttonpress, sheetupdate?). That is, the first entry to column "A" in "A3" will be put in "A4", second entry to "A3" should be put in "A5" and so on. Same goes for each column, independently. Also, if possible, I want cells in Row 3 to be cleared in the end.
How do i do this?
Please, answer with full tutorial explanation or a heavily sourced one, because my experience with EXCEL and VBA is close to none.
For anyone else finding this answer, understand that each column is independent of the others so it doesn't matter if the row counts vary by column.
Paste the following code into the Worksheet you plan to use. This will monitor changes ONLY in row 3 (but all columns - you can alter to only monitor the seven columns you want to watch).
When a change is detected in row 3, the column is determined, then the last used ROW is found for that column. The value entered is moved to the first available row, the value entered on row 3 is erased, and the SUM in row 2 is updated to reflect the new sum range.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ColName As String
Dim lLastRow As Long ' Saves Last Row for any column
Dim lColumn As Long
' This will monitor changes made in row 3 only.
' - move entered value to end of column
' - erase row 3 value entered
' - change 'SUM' in row 2 to reflect new row
On Error GoTo Enable_Events ' Need this! If error, need to enable events!!
If Target.Row <> 3 Then Exit Sub ' Only track row 3 changes
Application.EnableEvents = False ' Turn off event tracking because we make changes
lColumn = Target.column ' Get column that's being used.
With ActiveSheet 'Find the last used row in a Column
lLastRow = .Cells(.Rows.Count, Target.column).End(xlUp).Row
End With
Cells(lLastRow + 1, Target.column).value = Target.value ' Move value to end
Target.value = "" ' Clear value entered
' Get Column name (A, B, C...) then create new SUM
ColName = Left(Cells(1, lColumn).Address(False, False), 1 - (lColumn > 26))
Cells(2, lColumn).Formula = "=SUM(" & ColName & "4:" & ColName & lLastRow + 1 & ")"
Enable_Events:
Application.EnableEvents = True
End Sub

sort two columns on excel while keeping blank cells

So I trying to sort a list of names that have favorite colors to each of those names. In other words I want to have the sort look like the following example: (A and B correspond columns while #'s correspond rows)
**A** **B** **A** **B**
1 Tim Red 1 Josh Black
2 Blue 2 Yellow
3 Purple 3 Maria Grey
4 Josh Yellow 4 Orange
5 Black 5 Pink
6 Maria Pink 6 Tim Blue
7 Orange 7 Purple
8 Grey 8 Red
I want it to sort the name first, and wherever that name goes, the colors follow its place and then sort the colors. Is there a way to do this without using VBA since I have no knowledge on how to use VBA. Any help would be very grateful and for the record, this is not for a class assignment.
I am currently using Microsoft Excel 2011 for Mac.
I'm not all that good with worksheet functions and stuff but I don't think you're going to be able to achieve what you want without using VBA.
Assuming Mac VBA is the same as on windows, the following code should get you started.
The Idea: Make a regular sort work by filling the blank 'name' cells and once the sort has completed remove the extra names. I haven't included the code to do the actual sorting but the two methods below should populate the empty cells and also empty them aferwards.
Public Sub InsertDuplicates()
Dim Sheet As Worksheet: Set Sheet = ThisWorkbook.Worksheets("Sheet1")
Dim Current As String: Current = ""
Dim Row As Integer: Row = 1
' Fill the blank cells in the names column
Do
If Sheet.Cells(Row, 2).Value2 = "" Then
' Break out of the loop
Exit Do
End If
If Sheet.Cells(Row, 1).Value2 = "" Then
' No name present, so populate cell with the current name
Sheet.Cells(Row, 1).Value2 = Current
Else
' A name has been found, set it as the current name
Current = Sheet.Cells(Row, 1).Value2
End If
' Goto the next row
Row = Row + 1
Loop
End Sub
Public Sub RemoveDuplicates()
Dim Sheet As Worksheet: Set Sheet = ThisWorkbook.Worksheets("Sheet1")
Dim Current As String: Current = ""
Dim Row As Integer: Row = 1
' Remove unwanted duplicate names in names column
Do
If Sheet.Cells(Row, 2).Value2 = "" Then
' Break out of the loop
Exit Do
End If
If Sheet.Cells(Row, 1).Value2 = Current Then
' Row is a duplicate so empty the value
Sheet.Cells(Row, 1).Value2 = ""
Else
' Row is different from the previous, store the value and continue
Current = Sheet.Cells(Row, 1).Value2
End If
' Goto the next row
Row = Row + 1
Loop
End Sub
Public Sub SortList()
' perform the sort (you can record a macro to get the code required)
End Sub
Public Sub DoIt()
' this is the main macro, call this sub to action a sort.
InsertDuplicates
SortList
RemoveDuplicates
End Sub
This can be done without VBA, using helper columns and a manual sort.
If you want to do this all the time instead of just once, you may want to consider changing your data architecture. Entering the name in a raw data sheet on every row, then build a pivot table that shows the sorted layout you are after.
Steps to do the sort manually:
Insert a header row in row 1 and put in labels for each column, i.e. Name, color.
Add another column and use this formula in cell C2 (copy down):
=IF(ISBLANK(A2),C1,A2)
Copy column C and paste over itself with Paste Special > Values. Now there are the names only in this column.
Use the sort dialog to sort by the new column first and by the color second. These are the settings before confirming the sort:
After the sort, you will see this:
Add another formula column with this formula starting in D2 and copied down:
=IF(C2<>C1,C2,"")
Copy column D, paste as values over column A. Delete the helper columns.

Resources