I have two cells for drop-down menu. Cell A1 is for brand name and B1 is for model name. I want that if in cell A1 Samsung is selected that in cell B1 only Samsung models to be enable. All the brand and models are listed in separated sheet.
Please let me know how to implement this as I am new to excel.
The solution is actually simpler than what you may think. I’ve made 2 suggestions below, the first doesn’t require VBA at all – the second one does. In both cases, you must start by correctly naming the Ranges where the model names are listed.
Name the Ranges (must be done for both options)
Using Samsung as the example, select the cells where all the Samsung model names are listed (must be contiguous) and name the range Samsung. Repeat for all the other model listings by brand name. You say that All the brand and models are listed on separated sheet so you know how to do this.
Option One – formula only
In cell B1, set the Data Validation as such: Allow: = List. Source: = =INDIRECT($A$1)
Now, when you change the selection in cell A1, the Source of the Data Validation changes to that brands' model list via the named range.
Pros: doesn’t require VBA. Simple to implement.
Cons: INDIRECT() is a Volatile function. When you change brands in A1, the last model used is left in cell B1 (until you change it) which may interfere with any formulas that reference the cell.
Option Two – VBA
Place the following code in the Worksheet Module area of the sheet where your Data Validation cells are.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo GetOut
Application.EnableEvents = False
Dim MyList As String
If Not Intersect(Range("A1"), Target) Is Nothing Then
With ActiveSheet.Range("B1")
.ClearContents
.Validation.Delete
MyList = Sheet1.Range("A1").Value
.Validation.Add Type:=xlValidateList, Formula1:="=" & MyList
End With
ActiveSheet.Range("B1").Value = ActiveSheet.Range(MyList).Cells(1, 1).Value
End If
Continue:
Application.EnableEvents = True
Exit Sub
GetOut:
MsgBox Err.Description
Resume Continue
End Sub
Pros: replaces the value in B1 with the first valid model number for that brand.
Cons: uses VBA so the file needs to be saved as a macro-enabled file type
Let me know how you go.
Related
For example. I want my intro sheet "Main Sheet" to have an option to switch the workbook between currencies. USD and AED at the rate of 3.68. Some cells are referencing other cells in different sheets, so I don't want to change the cell references, I only need to calculate the rate in specific cells within each sheet.
How can I accomplish this preferably using a check box or button for easy converting from the start. I'm using excel for Mac. Thank you
Create a cell with a validation drop-down allowing to choose between AED and USD. Convert that cell to a named range for easy referencing throughout the workbook. You might call it "Curr", short for "Currency" (short because it will be used often).
I recommend that you create a similar cell somewhere where you enter the rate, currently 3.68 but plan on changing the rate in that cell only and have it applied to all the workbook. Name that cell as "Rate".
Now all cells containing values which you may want switched would be subject to the following formula. =[CellValue] * IF(Curr = "AED", Rate, 1). This formula presumes that the values are all entered in USD. If they are entered in AED the formula should look as follows. = ROUND([CellValue] / IF(Curr = "AED", 1, Rate), 2)
As you see, this solution would require the original cell values to be recorded somewhere, meaning, the cells used for data capture can't be the same as the ones used for data display. If you wish to insist on capture and display being in the same cell you would need code to do the conversion.
On the face of it this seems simple: When the Curr selection is changed, all cells with affected values are re-calculated. In practise this would end in disaster because there are 1001 ways in which something might go wrong and then you would lose all your data, not knowing whether the values are USD or AED at that moment.
Therefore the starting point needs to be to separate data capture and data display. Once that is done workheet functions might well be not only the easiest but also the most efficient way of achieving what you want.
I'm going to assume that you want to have the conversion on the input cell and not all of your cells are formulas and that a lot of the cells you want to convert are values. You should seriously consider the answer to split out input vs display, it will be much more foolproof and protected from any logic that may break your workbook.
If you're keen on this pathe then do the following, but, before you do ... BACKUP YOUR WORKBOOK. Any tests I've done with the below code are not breaking but I don't have your workbook, therefore, I make no guarantees.
Firstly, you need a cell that gives you the current exchange rate. You need to give that cell a named range of ExchangeRate.
In my workbook, that cell contains a formula ...
=IF(B1="USD",1,3.68)
It looks like this ...
... and cell B1 has a validation attached to it that allows you to select from 2 currencies, AED or USD.
You said you want to be able to ensure that only a selection of cells will be converted. To make sure we ring fence just those cells, you need to create a named range ON EACH SHEET that includes all of those cells.
The name of that range needs to be called CellsToConvert and you can do that through the Name Manager. When creating the named range, make sure you specify the worksheet you're creating it for, do not selected the "Workbook" option.
... the below shows the sporadic range I used on the first sheet. All coloured cells a part of that range. The green cells contain values and the yellow cells contain formulas.
At the end of the day, that range can be huge and across different sheets but it should work.
Now, add the following code into the ThisWorkbook object within the VBA editor ...
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim objCell As Range, dblExRate As Double, strFormula As String, objSheet As Worksheet
Dim strNewFormula As String, strOpeningChar As String, bIsFormula As Boolean
Dim objCells As Range, strError As String, strExRateRangeName As String
strExRateRangeName = "ExchangeRate"
dblExRate = Range(strExRateRangeName)
Application.EnableEvents = False
For Each objSheet In Worksheets
On Error Resume Next
strError = ""
Err.Clear
Set objCells = objSheet.Range("CellsToConvert")
strError = Err.Description
On Error GoTo 0
If strError = "" Then
For Each objCell In objCells
strFormula = objCell.FormulaR1C1
bIsFormula = False
' Check to make sure this field contains a formula.
If Left(strFormula, 1) = "=" And objCell.NumberFormat <> "#" Then
bIsFormula = True
End If
If dblExRate = 1 Then
' Base currency selected.
' Check to see if the cell contains a formula, if it does,
' convert it back to a value
If bIsFormula Then
' It's a formula and the cell is not set to text, proces it back
' to its original value, that could still be a formula.
' Remove all of the exchange rate components we would've added as
' a part of this routine.
strNewFormula = Replace(strFormula, ") * " & strExRateRangeName, "")
' Check to see if the formula has changed against the previous statement,
' if it has, then it contained the custom additions, otherwise, it didn't.
If strFormula <> strNewFormula Then
strNewFormula = Mid(strNewFormula, 3)
' Check to see if the new value is numeric, if it is, remove the leading
' equals sign as it wasn't originally a formula, or, at least it doesn't
' need to be a formula.
If IsNumeric(strNewFormula) Then
objCell.Value = strNewFormula
Else
objCell.FormulaR1C1 = "=" & strNewFormula
End If
End If
End If
Else
' Something other than the base currency has been selected.
strNewFormula = objCell.FormulaR1C1
If InStr(1, strNewFormula, strExRateRangeName, vbTextCompare) = 0 Then
If bIsFormula Then strNewFormula = Mid(objCell.FormulaR1C1, 2)
objCell.FormulaR1C1 = "=(" & strNewFormula & ") * " & strExRateRangeName
End If
End If
Next
End If
Next
Application.EnableEvents = True
End Sub
... once you've done all of the above, it should work for you. Performance could be tested if the workbook is large but that's something you'll need to check for yourself.
If you change a cell and it's within one of those ranges AND the currency of USD is not selected, you'll see the input value changed to a formula after you hit enter. That's pretty neat when you think about it but may not be for you.
One last thing to note, if your range contains broken links, the calculation for that sheet will fail and my code will not notify you of that.
This adds another option for you but is riskier than the first answer. There's nothing like options. :-)
How might one turn spreadsheet cells into buttons, and execute VBA code, without inserting buttons, shapes or other active-X objects?
Using #TimWilliams' suggestion and referenced URL, based on readings there and further, I present some demonstration code, which works for me in Excel 2010: the IfError may not work in earlier versions, and I wonder if it behaves different in later versions.
Note: This code can not be debugged as one might with normal VBA. This is because it is executed on the "spreadsheet side", as a user defined function.
Place a formula in a cell (here, A2):
=IFERROR(HYPERLINK("#MyUDF()","CellText"),"Junk")
"CellText" will show in cell A2.
The "#...." points to the UDF. In combination with the Set statement in the code, it forces a "click" to execute, and only executes once on the click, rather than as a repeatable event executed when hovering and moving across the cell
The =IFERROR(HYPERLINK(...),...) is a workaround for the #name or other error., seen when using the mere =HYPERLINK(....).
Place this code in a module (a dimension and the UDF):
Dim j as integer
Function MyUDF() ' this is a user-defined-function
'NOTE: can't be traced when executed,
'so this creates debugging issues
Set MyUDF = Selection
Range("a1") = j
j = j + 1
End Function
Clicking on the URL in A2 will increment the value displayed in A1 - one increment per click.
To observe the hover effect:
Comment out the "Set Statement"
remove the quotes and pound sign around the UDF reference. The cell will now show "asdf" instead of "Test".
Roll across the URL, and cell A1 will increment as you move/hover.
To get the entire cell to cause execution of the UDF (and the incrementing value), turn on word wrap for the cell.
Notice how with the hover, the code is executed often as you move around in the cell. For me, the code does not execute if I stop moving while in the cell.
An Alternative to "putting a button in a cell"
Select a cell to execute code using the worksheet event: Worksheet_SelectionChange
Place the code in the specific sheet's module, not the WorkBook Module. Color/Border/Text the cell as you please; a cell-is-a-cell on any computer or screen. I use this to reference help loaded into a userForm, from a look up on a help worksheet, when the user clicks on a short label/description. This works on merged cells as buttons. Using cell/buttons avoids Active-X objects complaints from IT.
Things to think on, with the sample code, following:
Target.Address returns absolute addresses, using the "$" character
Use the Select Case in your code, even if you have one cell/button. This eases the path to adding cell/buttons, later
consider using named ranges on the spreadsheet, and reference them in the code. That way, VBA won't care if you move the cell/button
If you have merged cells for which you create a named range, remember that the named range, in the spreadsheet, only points to the top-left cell
However, the Target.Address for the merged area returns the full range, not just one cell. If your Select Case refers to the address of the Target's top-left cell, you avoid this problem.
use Target.Cells(1,1).Address
Bad choice for merged cells: don't use MergeArea.Address (MergeArea will not work on merged cells [only works on single cells]; it returns the merged range within which a cell lives.
*Sample Code*
'How to Make Cells into Buttons that execute code
' place code in the specific Worksheet module of interest
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' in this example, I create named ranges on the spreadsheet '
' [complicated names, here, so you can read what's what]:
' one cell: "Button_OneCellNameRange"
' one set of merged cells: "Button_MergedCellNameRange"
' [the reference is the top-left cell, only]
' a VBA created cell/button location [not very useful for later sheet edits]
Dim myVBACellButton As Range
Set myVBACellButton = Range("B2")
Debug.Print "Target Address: " & Target.Address
'merged cells will return a range: eg "$A$1:$D$3"
Debug.Print "Target.Cells(1,1).Address: " & Target.Cells(1, 1).Address
'merged cells will return the top left cell, which would match
' a named reference to a merged cell
Select Case Target.Cells(1, 1).Address
'if you have merged cells, you must use the ".cells(1,1).address"
' and not just Target.Address
Case Is = "$A$1"
MsgBox "Hello from: Click on A1"
' [execute a procedure/subroutine call, or more code, here...]
Case Is = myVBACellButton.Address
MsgBox "Hello from: Click on B2, a VBA referenced cell/button"
' "myCellButton" defined as range in VBA
'using a range named on the spreadsheet itself ...
' named ranges allow one to move the cell/button freely,
' without VBA worries
Case Range("Button_OneCellNameRange").Address
MsgBox "Hello From: Button Click on Button_OneCellNameRange"
Case Range("Button_MergedCellNamedRange").Address
'note that the address for merged cells is ONE CELL, the top left
MsgBox _
"Hello from: Button_MergedCellNamedRange.Address: " _
& Range("Button_MergedCellNamedRange").Address _
Case Else ' normally you wouldn't be using this, for buttons
MsgBox "NOT BUTTONS"
End Select
End Sub
I need help with clearing/changing a dependent drop down list in excel 2013, without using a macro, if it's possible. I've tried different workarounds, but nothing is working:
This is one of the things I tried:
=INDIRECT(VLOOKUP($A$8, lookuptable, 2, FALSE))
This doesn't work, the dependent (child) drop down cell is not being cleared/changed when the parent (A8) drop down is changed, causing a miss-match.
Thanks!
The technique for dependent data validation is to use range names for each dependent data list. The range name is the same as the value selected in the parent list. Example: the parent data validation cell has a list of countries.
You also build several lists, one for each country, with the cities of that country. The range names for each list are the country names.
Apply the country DV to A1.
Then build another range name to use in the dependent data validation for the city cell, e.g. ListRange. The formula to build the range name is
=Indirect($A$1)
The dependent data validation then points to the range that has the same name as the value in cell A1. This is a dynamic range and will change when the selection in cell A1 changes.
This will not clear any existing choice in the dependent data validation cell. E.g, if your first DV cell has a list of countries and the dependent DV has a list of cities, selecting a country in A1 will change the DV list for the city cell and a city can be selected (France > Paris). But if the country cell is changed to Italy, the city cell will still show Paris, while the DV drop down now lists cities in Italy.
In order to clear the selected city when the country cell is changes, you will indeed need VBA.
This is the best I have come up with, pick the country in cell A2 and the city will change BUT only according to the position specified in cell A4. I hope it may help you, cheers.
I have a sample piece of code I use for a similar instance, one dropdown list with 3 options using an indirect formula to provide different choices per option.
I use named ranges and indirect formula via data validation.
When I change my list value in my dropdown cell "D2" in this example, it will then clear the second dropdown list in "F2" (2 columns to the right or offset by 2). This then enables the user to select from new choices dependant on the option change...
Hope this helps.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$D$2" Then
If Target.Validation.Type = "$F$2" Then
Application.EnableEvents = False
Target.Offset(0, 2).ClearContents
End If
End If
exitHandler:
Application.EnableEvents = True
Exit Sub
End Sub
Good Morning/Afternoon/Evening to all :)
My First time on here so.................... :)
Spreadsheet Example
I use this code in "Conditional Formatting"
=AND(ISNUMBER(SEARCH($B$3,A6)),$B$3<>””)
so i only able to highlight the cell as on Screenshot (Whenever type text on B3 it's automatically highlight the contain Cell as on Screenshot) but what I want is it's only highlight the cell but cannot jump (select) cell when i type ""text"" on Search B3 box.
For Example: On Screenshot I type DW353 and It's highlight in Redcolor on A18 Cell No. but if i type other text as DW364, 365 and on which located on A24, A25 and continue to down, it's only highlight the specific Cell and I have to Search (Scroll up and down) for look that RED Highlight. What i want is whenever i type a "Text" on B3 it's Highlight and direct Jump on Contain Cell as (Find and Replace).
Thank you in Advance and Sorry for Long Question :)
The easiest way to accomplish this kind of functionality is to use VBA to trigger the Advanced Filter functionality, so that all other rows are hidden.
Here's how:
Add a Named Range called "MyList" covering the entire range of data in the MACHINE NO: column that you want to filter. (Best if you turn this block of data into an Excel Table, and then just reference the MACHINE NO column, as this will mean the named range is dynamic i.e. it will automatically adjust should the underlying data grow).
Put the text "MACHINE NO:" in B2
Add a Named Range called "Criteria" covering B2:B3
Add a Named Range called "Input" covering B3
This should look something like the below:
Put this code in the Sheet Module that corresponds to the Per Machine Movement tab (and NOT in a standard Code Module) :
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("Input")) Is Nothing Then
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0
Range("MyList").AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=Range("Criteria"), Unique:=False
End If
End Sub
End Sub
i.e. like so:
Now, any time someone enters a Machine Number, the sheet will be filtered to show just the row of interest:
You can find a working example at Daniel Ferry's excellent blog, at the following link:
http://www.excelhero.com/blog/2010/07/excel-partial-match-database-lookup.html
Look for the second sample file he posted under the heading --- UPDATE ---
This approach can be tweaked to search across multiple columns, as per your follow-up question. First, here's the setup of the Named Ranges (including a new one above the input cell called "Header"):
...and here's the amended code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vRanges As Variant
Dim vItem As Variant
If Not Intersect(Target, Range("Input")) Is Nothing Then
On Error GoTo errhandler
With Application
.EnableEvents = False
.ScreenUpdating = False
.Calculation = xlManual
End With
'Clear any existing filter
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0
'Cycle through the search arrays one by one, and run the advanced filter until you find a match
vRanges = Array("Range1", "Range2", "Range3", "Range4") '<<< Change these to match your range names
For Each vItem In vRanges
Range("Header") = Range(vItem).Cells(1)
Range(vItem).AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=Range("Criteria"), Unique:=False
If Range(vItem).SpecialCells(xlCellTypeVisible).Count > 1 Then Exit For
Next vItem
errhandler:
With Application
.EnableEvents = True
.ScreenUpdating = True
.Calculation = xlAutomatic
End With
End If
End Sub
And here's a couple of screenshots showing it matching on different columns:
You can format cell B2 so that it can't be seen if you want.
I would suggest turning the different input areas in your workbook into Excel Tables (also known as ListObjects) before you set up the "RangeX" named ranges. That's because under the hood, Tables are basically dynamic named ranges that automatically expand to accommodate new data. So if you then manually set up a Named Range that points at a Table column, you never need to remember to adjust your Named Ranges in order to handle new data, because the Table automatically does this for you. See the image below:
Note that you can change the formatting of Tables using the Table Styles option in the ribbon, or even turn off the formatting entirely:
I am trying the folowing since a few days but due to my lack of VBA skills don't get it working.
Scenario:
User: Selects a value from dropdown list (cells allow only a list
defined in another sheet).
Code: Copy the value left to the appropriate list value. (This is a list of names.)
Code: Paste the value into a specific field in sheet one.
Example:
The user is picking the value "Team One" from a dropdownlist in A1 in sheet one. This list is defined on sheet two. Next to each item of the list on sheet two is a cell with a comma separated list of names.
After the user has picked a team from the dropdown list, the corresponding list of names is copied into the field B1 in sheet one.
This procedure should only be fired when A1 is changed.
Hope I could make myself clear. If I finally find the solution myself, I will post it here.
Thank you for reading this.
You can do this without VBA. In the field you want the list of names pasted into enter this formula:
=IF(ISBLANK(<address of dropdown on Sheet1>),"",INDEX(<address of list to left of values on Sheet2>,MATCH(<address of dropdown on Sheet1>,<address of dropdown values on Sheet2>,0)))
This will be blank when nothing is selected from the dropdown and will display the appropriate list of names when a value is selected.
For example, if the dropdown is in B1 on Sheet1, the dropdown values are in B1:B9 on Sheet2, and the corresponding list of names are in A1:A9 on Sheet2, you would use this formula:
=IF(ISBLANK(Sheet1!B1),"",INDEX(Sheet2!A1:A9,MATCH(Sheet1!B1,Sheet2!B1:B9,0)))
EDIT (per comment):
To use this in VBA, you'll need to do something similar to what #chris neilsen suggested. In the Worksheet module, you'll need to create a sub for a change event:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("B1")) Is Nothing Then
Range("A1").Formula = "=INDEX(Sheet2!A1:A9,MATCH(Sheet1!B1,Sheet2!B1:B9,0))"
If IsError(Range("A1").Value) Then
Range("A1") = ""
Else
Range("A1").Value = Range("A1")
End If
End If
End Sub
To remove any confusion, A1 is the cell that will display the output.
To do this as VBA, you would do something like the following. Per your original question, there is a list on Sheet2 that corresponds to the selection from the dropdown box and populates on Sheet1.
In the VBA editor:
In Sheet1, add the following methods
Private Sub ComboBox1_Change()
If ComboBox1.Text <> "Select" Then
Dim selVal As String
selVal = ComboBox1.Text
Range("B1").Value = GetList(selVal)
End If
End Sub
Public Function GetList(ByVal Value As String) As Variant
Dim result As Variant
result = Application.VLookup(Value, Worksheets("Sheet2").Range("A1:B100"), 2, False)
GetList = result
End Function
In the workbook object code, enter the following method:
Private Sub Workbook_Open()
With ThisWorkbook.Worksheets("Sheet1").ComboBox1
.AddItem "Team One"
.AddItem "Team Two"
.AddItem "Team Three"
.AddItem "Team Four"
.AddItem "Team Five"
.Text = IIf(.Text = "", "Select", .Text)
End With
Worksheets("Sheet1").Activate
End Sub
I should note that you could do this without any vba by simply using a a list control found in the Data Validation option in Excel. When you make a selection change in that, you would then use a standard VLookup in cell B1 to grab the corresponding value(s).
To implement this in VBA, use a Change event to monitor the data entry cell.
Assuming you have named your validation data range as ListData, put his in the module for Sheet1
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then
[B1] = Application.WorksheetFunction.VLookup(Target.Value, [ListData].Resize(, 2), 2, 0)
End If
End Sub
I would advocate an approach similar to the one that Excellll described, but with VLOOKUP rather than MATCH. To do this, you'd need to have your lists of names to the right of each team's name. For example:
| A | B
1 |Team 1 |Albert, Beth
2 |Team 2 |Carlo, Delia
3 |Team 3 |Egbert, Frederika
Now, if the team's name is at cell B7, you could use this formula to get the associated list of names:
=VLOOKUP(B7, Sheet2!$A$1:$B$3, 2, FALSE)
EDIT
See Doug Glancy's comment below explaining why Excellll's solution is better than using VLOOKUP.